Add BRACT for distributed contour tree computation

This merge request is Phase 1 of several to implement the distributed parallel
contour tree in VTKm. This merge requests adds the base outline for the
algorithm. The implementation of the details of the algorithm in the
BoundaryRestrictedAugmentedContourTree.h is currently still missing.
However, these will require a substantial (~3000) lines of additional code.
The goal is to stage the integration process across merge requests to make
the review process simpler.
This commit is contained in:
Oliver Ruebel 2020-06-12 11:50:01 -06:00 committed by Kenneth Moreland
parent 22f227a91e
commit 66c96a983f
76 changed files with 8854 additions and 774 deletions

@ -16,6 +16,7 @@ if(VTKm_ENABLE_EXAMPLES)
add_subdirectory(clipping)
add_subdirectory(contour_tree)
add_subdirectory(contour_tree_augmented)
add_subdirectory(contour_tree_distributed)
add_subdirectory(cosmotools)
add_subdirectory(demo)
#add_subdirectory(game_of_life)

@ -65,6 +65,7 @@ vtkm_add_target_information(ContourTree_Augmented
DEVICE_SOURCES ContourTreeApp.cxx)
option (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT Off)
mark_as_advanced(VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
if (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
target_compile_definitions(ContourTree_Augmented PRIVATE "DEBUG_PRINT")
endif()
@ -85,6 +86,7 @@ if (VTKm_ENABLE_MPI)
target_compile_definitions(ContourTree_Augmented_MPI PRIVATE "WITH_MPI")
option (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT Off)
mark_as_advanced(VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
if (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
target_compile_definitions(ContourTree_Augmented_MPI PRIVATE "DEBUG_PRINT")
endif()

@ -459,7 +459,7 @@ int main(int argc, char* argv[])
// 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::filter::GetRowsColsSlices temp;
vtkm::worklet::contourtree_augmented::GetRowsColsSlices temp;
temp(inDataSet.GetCellSet(), nRows, nCols, nSlices);
dims[0] = nRows;
dims[1] = nCols;

@ -0,0 +1,78 @@
##============================================================================
## 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)
##==============================================================================
cmake_minimum_required(VERSION 3.8...3.15 FATAL_ERROR)
# Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
####################################
# MPI
####################################
if (VTKm_ENABLE_MPI)
add_executable(ContourTree_Distributed ContourTreeApp.cxx)
target_link_libraries(ContourTree_Distributed vtkm_filter)
vtkm_add_target_information(ContourTree_Distributed
MODIFY_CUDA_FLAGS
DEVICE_SOURCES ContourTreeApp.cxx)
target_compile_definitions(ContourTree_Distributed PRIVATE)
option (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT Off)
mark_as_advanced(VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
if (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
target_compile_definitions(ContourTree_Distributed PRIVATE "DEBUG_PRINT")
endif()
if (TARGET vtkm::tbb)
target_compile_definitions(ContourTree_Distributed PRIVATE "ENABLE_SET_NUM_THREADS")
endif()
endif()

@ -0,0 +1,573 @@
//============================================================================
// 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 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/filter/ContourTreeUniformDistributed.h>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#ifdef ENABLE_SET_NUM_THREADS
#include "tbb/task_scheduler_init.h"
#endif
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/Configure.h>
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
#include <mpi.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>
#include <utility>
#include <vector>
using ValueType = vtkm::Float32;
namespace ctaug_ns = vtkm::worklet::contourtree_augmented;
// Simple helper class for parsing the command line options
class ParseCL
{
public:
ParseCL() {}
void parse(int& argc, char** argv)
{
mCLOptions.resize(static_cast<std::size_t>(argc));
for (std::size_t i = 1; i < static_cast<std::size_t>(argc); ++i)
{
this->mCLOptions[i] = std::string(argv[i]);
}
}
vtkm::Id findOption(const std::string& option) const
{
auto it =
std::find_if(this->mCLOptions.begin(),
this->mCLOptions.end(),
[option](const std::string& val) -> bool { return val.find(option) == 0; });
if (it == this->mCLOptions.end())
{
return -1;
}
else
{
return (it - this->mCLOptions.begin());
}
}
bool hasOption(const std::string& option) const { return this->findOption(option) >= 0; }
std::string getOption(const std::string& option) const
{
std::size_t index = static_cast<std::size_t>(this->findOption(option));
std::string val = this->mCLOptions[index];
auto valPos = val.find("=");
if (valPos)
{
return val.substr(valPos + 1);
}
return std::string("");
}
const std::vector<std::string>& getOptions() const { return this->mCLOptions; }
private:
std::vector<std::string> mCLOptions;
};
// Compute and render an isosurface for a uniform grid example
int main(int argc, char* argv[])
{
// Setup the MPI environment.
MPI_Init(&argc, &argv);
auto comm = MPI_COMM_WORLD;
// Tell VTK-m which communicator it should use.
vtkm::cont::EnvironmentTracker::SetCommunicator(vtkmdiy::mpi::communicator(comm));
// get the rank and size
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 =
vtkm::cont::InitializeOptions::RequireDevice;
vtkm::cont::InitializeResult vtkm_config =
vtkm::cont::Initialize(argc, argv, vtkm_initialize_options);
auto device = vtkm_config.Device;
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Info, rank == 0, "Running with MPI. #ranks=" << size);
// Setup timing
vtkm::Float64 prevTime = 0;
vtkm::Float64 currTime = 0;
vtkm::cont::Timer totalTime;
totalTime.Start();
////////////////////////////////////////////
// Parse the command line options
////////////////////////////////////////////
ParseCL parser;
parser.parse(argc, argv);
std::string filename = parser.getOptions().back();
bool useMarchingCubes = false;
if (parser.hasOption("--mc"))
useMarchingCubes = true;
#ifdef ENABLE_SET_NUM_THREADS
int numThreads = tbb::task_scheduler_init::default_num_threads();
if (parser.hasOption("--numThreads"))
{
bool deviceIsTBB = (device.GetName() == "TBB");
// Set the number of threads to be used for TBB
if (deviceIsTBB)
{
numThreads = std::stoi(parser.getOption("--numThreads"));
tbb::task_scheduler_init schedulerInit(numThreads);
}
// Print warning about mismatch between the --numThreads and -d/--device option
else
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"WARNING: Mismatch between --numThreads and -d/--device option."
"numThreads option requires the use of TBB as device. "
"Ignoring the numThread option.");
}
}
#endif
if (rank == 0 && (argc < 2 || parser.hasOption("--help") || parser.hasOption("-h")))
{
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;
MPI_Finalize();
return EXIT_SUCCESS;
}
if (rank == 0)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " ------------ Settings -----------"
<< std::endl
<< " filename="
<< filename
<< std::endl
<< " device="
<< device.GetName()
<< std::endl
<< " mc="
<< useMarchingCubes
<< std::endl
#ifdef ENABLE_SET_NUM_THREADS
<< " numThreads="
<< numThreads
<< std::endl
#endif
<< " nblocks="
<< numBlocks
<< std::endl);
}
currTime = totalTime.GetElapsedTime();
vtkm::Float64 startUpTime = currTime - prevTime;
prevTime = currTime;
// 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);
int out = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
if (-1 == out)
{
perror("opening cout.log");
return 255;
}
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));
if (-1 == dup2(out, fileno(stdout)))
{
perror("cannot redirect stdout");
return 255;
}
if (-1 == dup2(err, fileno(stderr)))
{
perror("cannot redirect stderr");
return 255;
}
delete[] cstr_filename;
#endif
///////////////////////////////////////////////
// Read the input data
///////////////////////////////////////////////
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::vector<std::size_t> dims;
std::string line;
getline(inFile, line);
std::istringstream linestream(line);
std::size_t dimVertices;
while (linestream >> dimVertices)
{
dims.push_back(dimVertices);
}
// 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>()));
// 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
<< std::endl
<< " Number of mesh vertices: "
<< numVertices
<< 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)
{
MPI_Finalize();
return EXIT_SUCCESS;
}
// Read data
std::vector<ValueType> values(numVertices);
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
{
inFile >> values[vertex];
}
// 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::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]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(dims[2]))
: vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(0));
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();
{
vtkm::Id lastDimSize =
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
if (size > (lastDimSize / 2.))
{
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
rank == 0,
"Number of ranks to large for data. Use " << lastDimSize / 2
<< "or fewer ranks");
MPI_Finalize();
return EXIT_FAILURE;
}
vtkm::Id standardBlockSize = (vtkm::Id)(lastDimSize / numBlocks);
vtkm::Id blockSize = standardBlockSize;
vtkm::Id blockSliceSize =
nDims == 2 ? static_cast<vtkm::Id>(dims[0]) : static_cast<vtkm::Id>((dims[0] * dims[1]));
vtkm::Id blockNumValues = blockSize * blockSliceSize;
vtkm::Id startBlock = blocksPerRank * rank;
vtkm::Id endBlock = startBlock + blocksPerRank;
for (vtkm::Id blockIndex = startBlock; blockIndex < endBlock; ++blockIndex)
{
vtkm::Id localBlockIndex = blockIndex - startBlock;
vtkm::Id blockStart = blockIndex * blockNumValues;
vtkm::Id blockEnd = blockStart + blockNumValues;
if (blockIndex < (numBlocks - 1)) // add overlap between regions
{
blockEnd += blockSliceSize;
}
else
{
blockEnd = lastDimSize * blockSliceSize;
}
vtkm::Id currBlockSize = (vtkm::Id)((blockEnd - blockStart) / blockSliceSize);
vtkm::cont::DataSet ds;
// 2D data
if (nDims == 2)
{
vtkm::Id2 vdims;
vdims[0] = static_cast<vtkm::Id>(currBlockSize);
vdims[1] = static_cast<vtkm::Id>(dims[0]);
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
vtkm::Vec<ValueType, 2> spacing(1, 1);
ds = dsb.Create(vdims, origin, spacing);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(blockIndex, 0, 0));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3((blockStart / blockSliceSize), 0, 0));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(currBlockSize, static_cast<vtkm::Id>(dims[0]), 0));
}
// 3D data
else
{
vtkm::Id3 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[0]);
vdims[1] = static_cast<vtkm::Id>(dims[1]);
vdims[2] = static_cast<vtkm::Id>(currBlockSize);
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
ds = dsb.Create(vdims, origin, spacing);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
localBlockSizesPortal.Set(
localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), static_cast<vtkm::Id>(dims[1]), currBlockSize));
}
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
(values.begin() + blockEnd));
//vtkm::cont::DataSetFieldAdd dsf;
ds.AddPointField("values", subValues);
inDataSet.AppendPartition(ds);
}
}
currTime = totalTime.GetElapsedTime();
vtkm::Float64 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);
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);
currTime = totalTime.GetElapsedTime();
vtkm::Float64 computeContourTreeTime = currTime - prevTime;
prevTime = currTime;
// 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)
{
int temp;
MPI_Status status;
MPI_Recv(&temp, 1, MPI_INT, (rank - 1), 0, comm, &status);
}
currTime = totalTime.GetElapsedTime();
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " -------------------------- Totals "
<< rank
<< " -----------------------------"
<< std::endl
<< std::setw(42)
<< std::left
<< " Start-up"
<< ": "
<< startUpTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Data Read"
<< ": "
<< dataReadTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Build VTKM Dataset"
<< ": "
<< buildDatasetTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Compute Contour Tree"
<< ": "
<< computeContourTreeTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Total Time"
<< ": "
<< currTime
<< " seconds");
// Flush ouput streams just to make sure everything has been logged (in particular when using MPI)
std::cout << std::flush;
std::cerr << std::flush;
// Let the next rank know that it is time to print their summary.
if (rank < (size - 1))
{
int message = 1;
MPI_Send(&message, 1, MPI_INT, (rank + 1), 0, comm);
}
MPI_Finalize();
return EXIT_SUCCESS;
}

@ -19,6 +19,7 @@ set(headers
Contour.h
ContourTreeUniform.h
ContourTreeUniformAugmented.h
ContourTreeUniformDistributed.h
CoordinateSystemTransform.h
CreateResult.h
CrossProduct.h
@ -92,6 +93,7 @@ set(header_template_sources
Contour.hxx
ContourTreeUniform.hxx
ContourTreeUniformAugmented.hxx
ContourTreeUniformDistributed.hxx
CoordinateSystemTransform.hxx
CrossProduct.hxx
DotProduct.hxx

@ -57,23 +57,17 @@
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/worklet/contourtree_augmented/ContourTree.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_distributed/MultiBlockContourTreeHelper.h>
#include <utility>
#include <vector>
#include <vtkm/Bounds.h>
#include <vtkm/filter/FilterCell.h>
#include <memory>
namespace vtkm
{
namespace filter
{
namespace detail
{
class MultiBlockContourTreeHelper;
} // namespace detail
/// \brief Construct the Contour Tree for a 2D or 3D regular mesh
///
/// This filter implements the parallel peak pruning algorithm. In contrast to
@ -185,52 +179,8 @@ private:
/// 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
detail::MultiBlockContourTreeHelper* MultiBlockTreeHelper;
};
///
/// Helper struct to collect sizing information from the dataset
///
struct GetRowsColsSlices
{
//@{
/// Get the number of rows, cols, and slices of a vtkm::cont::CellSetStructured
/// @param[in] cells The input vtkm::cont::CellSetStructured
/// @param[out] nRows Number of rows (x) in the cell set
/// @param[out] nCols Number of columns (y) in the cell set
/// @param[out] nSlices Number of slices (z) in the cell set
void operator()(const vtkm::cont::CellSetStructured<2>& cells,
vtkm::Id& nRows,
vtkm::Id& nCols,
vtkm::Id& nSlices) const
{
vtkm::Id2 pointDimensions = cells.GetPointDimensions();
nRows = pointDimensions[0];
nCols = pointDimensions[1];
nSlices = 1;
}
void operator()(const vtkm::cont::CellSetStructured<3>& cells,
vtkm::Id& nRows,
vtkm::Id& nCols,
vtkm::Id& nSlices) const
{
vtkm::Id3 pointDimensions = cells.GetPointDimensions();
nRows = pointDimensions[0];
nCols = pointDimensions[1];
nSlices = pointDimensions[2];
}
//@}
/// Raise ErrorBadValue if the input cell set is not a vtkm::cont::CellSetStructured<2> or <3>
template <typename T>
void operator()(const T& cells, vtkm::Id& nRows, vtkm::Id& nCols, vtkm::Id& nSlices) const
{
(void)nRows;
(void)nCols;
(void)nSlices;
(void)cells;
throw vtkm::cont::ErrorBadValue("Expected 2D or 3D structured cell cet! ");
}
std::unique_ptr<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>
MultiBlockTreeHelper;
};
} // namespace filter

@ -53,23 +53,12 @@
#ifndef vtk_m_filter_ContourTreeUniformAugmented_hxx
#define vtk_m_filter_ContourTreeUniformAugmented_hxx
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/filter/ContourTreeUniformAugmented.h>
#include <vtkm/worklet/ContourTreeUniformAugmented.h>
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/worklet/contourtree_augmented/Mesh_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/ContourTreeMesh.h>
#include <vtkm/cont/ArrayCopy.h>
//#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/BoundsCompute.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/IdRelabler.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/Configure.h>
@ -77,83 +66,11 @@ VTKM_THIRDPARTY_PRE_INCLUDE
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
#include <vtkm/worklet/contourtree_distributed/ContourTreeBlockData.h>
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
#include <vtkm/worklet/contourtree_distributed/MergeBlockFunctor.h>
namespace vtkm
{
namespace filter
{
namespace detail
{
template <typename FieldType>
struct ContourTreeBlockData
{
static void* create() { return new ContourTreeBlockData<FieldType>; }
static void destroy(void* b) { delete static_cast<ContourTreeBlockData<FieldType>*>(b); }
// 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::cont::ArrayHandle<FieldType> SortedValue;
vtkm::worklet::contourtree_augmented::IdArrayType GlobalMeshIndex;
vtkm::worklet::contourtree_augmented::IdArrayType Neighbours;
vtkm::worklet::contourtree_augmented::IdArrayType FirstNeighbour;
vtkm::Id MaxNeighbours;
// Block metadata
vtkm::Id3 BlockOrigin; // Origin of the data block
vtkm::Id3 BlockSize; // Extends of the data block
vtkm::Id3 GlobalSize; // Extends of the global mesh
unsigned int ComputeRegularStructure; // pass through augmentation setting
};
} // namespace detail
} // namespace filter
} // namespace vtkm
namespace vtkmdiy
{
// Struct to serialize ContourBlockData objects (i.e., load/save) needed in parralle for DIY
template <typename FieldType>
struct Serialization<vtkm::filter::detail::ContourTreeBlockData<FieldType>>
{
static void save(vtkmdiy::BinaryBuffer& bb,
const vtkm::filter::detail::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);
vtkmdiy::save(bb, block.FirstNeighbour);
vtkmdiy::save(bb, block.MaxNeighbours);
vtkmdiy::save(bb, block.BlockOrigin);
vtkmdiy::save(bb, block.BlockSize);
vtkmdiy::save(bb, block.GlobalSize);
vtkmdiy::save(bb, block.ComputeRegularStructure);
}
static void load(vtkmdiy::BinaryBuffer& bb,
vtkm::filter::detail::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);
vtkmdiy::load(bb, block.FirstNeighbour);
vtkmdiy::load(bb, block.MaxNeighbours);
vtkmdiy::load(bb, block.BlockOrigin);
vtkmdiy::load(bb, block.BlockSize);
vtkmdiy::load(bb, block.GlobalSize);
vtkmdiy::load(bb, block.ComputeRegularStructure);
}
};
} // namespace mangled_vtkmdiy_namespace
#include <memory>
namespace vtkm
{
@ -179,379 +96,6 @@ struct PostExecuteCaller
}
};
// --- Helper class to store the spatial decomposition defined by the PartitionedDataSet input data
class SpatialDecomposition
{
public:
VTKM_CONT
SpatialDecomposition(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)
: BlocksPerDimension(blocksPerDim)
, GlobalSize(globalSize)
, LocalBlockIndices(localBlockIndices)
, LocalBlockOrigins(localBlockOrigins)
, LocalBlockSizes(localBlockSizes)
{
}
inline vtkmdiy::DiscreteBounds GetVTKmDIYBounds() const
{
if (this->NumberOfDimensions() == 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]);
return domain;
}
else
{
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]);
domain.max[2] = static_cast<int>(this->GlobalSize[2]);
return domain;
}
}
inline vtkm::Id NumberOfDimensions() const { return GlobalSize[2] > 1 ? 3 : 2; }
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return BlocksPerDimension[0] * BlocksPerDimension[1] * BlocksPerDimension[2];
}
inline vtkm::Id GetLocalNumberOfBlocks() const { return LocalBlockSizes.GetNumberOfValues(); }
// Number of blocks along each dimension
vtkm::Id3 BlocksPerDimension;
// Size of the global mesh
vtkm::Id3 GlobalSize;
// Index of the local blocks in x,y,z, i.e., in i,j,k mesh coordinates
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockIndices;
// Origin of the local blocks in mesh index space
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockOrigins;
// Size of each local block in x, y,z
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockSizes;
};
//--- Helper class to help with the contstuction of the GlobalContourTree
class MultiBlockContourTreeHelper
{
public:
VTKM_CONT
MultiBlockContourTreeHelper(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)
: MultiBlockSpatialDecomposition(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes)
{
vtkm::Id localNumBlocks = this->GetLocalNumberOfBlocks();
LocalContourTrees.resize(static_cast<std::size_t>(localNumBlocks));
LocalSortOrders.resize(static_cast<std::size_t>(localNumBlocks));
}
VTKM_CONT
~MultiBlockContourTreeHelper(void)
{
LocalContourTrees.clear();
LocalSortOrders.clear();
}
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 vtkm::Id GetLocalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks();
}
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks();
}
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;
}
// Used to compute the local contour tree mesh in after DoExecute. I.e., the function is
// used in PostExecute to construct the initial set of local ContourTreeMesh blocks for
// DIY. Subsequent construction of updated ContourTreeMeshes is handled separately.
template <typename T>
inline static vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>*
ComputeLocalContourTreeMesh(const vtkm::Id3 localBlockOrigin,
const vtkm::Id3 localBlockSize,
const vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<T>& field,
const vtkm::worklet::contourtree_augmented::ContourTree& contourTree,
const vtkm::worklet::contourtree_augmented::IdArrayType& sortOrder,
unsigned int computeRegularStructure)
{
vtkm::Id startRow = localBlockOrigin[0];
vtkm::Id startCol = localBlockOrigin[1];
vtkm::Id startSlice = localBlockOrigin[2];
vtkm::Id numRows = localBlockSize[0];
vtkm::Id numCols = localBlockSize[1];
vtkm::Id totalNumRows = globalSize[0];
vtkm::Id totalNumCols = globalSize[1];
// compute the global mesh index and initalize the local contour tree mesh
if (computeRegularStructure == 1)
{
// Compute the global mesh index
vtkm::worklet::contourtree_augmented::IdArrayType localGlobalMeshIndex;
auto transformedIndex = vtkm::cont::ArrayHandleTransform<
vtkm::worklet::contourtree_augmented::IdArrayType,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabler>(
sortOrder,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabler(
startRow, startCol, startSlice, numRows, numCols, totalNumRows, totalNumCols));
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
// Compute the local contour tree mesh
auto localContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>(
contourTree.Arcs, sortOrder, field, localGlobalMeshIndex);
return localContourTreeMesh;
}
else if (computeRegularStructure == 2)
{
// 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(contourTree.Augmentnodes, sortOrder);
auto transformedIndex = vtkm::cont::make_ArrayHandleTransform(
permutedSortOrder,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabler(
startRow, startCol, startSlice, numRows, numCols, totalNumRows, totalNumCols));
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
// Compute the local contour tree mesh
auto localContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>(
contourTree.Augmentnodes, contourTree.Augmentarcs, sortOrder, field, localGlobalMeshIndex);
return localContourTreeMesh;
}
else
{
// We should not be able to get here
throw vtkm::cont::ErrorFilterExecution(
"Parallel contour tree requires at least parial boundary augmentation");
}
}
SpatialDecomposition MultiBlockSpatialDecomposition;
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> LocalContourTrees;
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> LocalSortOrders;
}; // end MultiBlockContourTreeHelper
// Functor needed so we can discover the FieldType and DeviceAdapter template parameters to call MergeWith
struct MergeFunctor
{
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>
void MergeBlockFunctor(
ContourTreeBlockData<FieldType>* block, // local Block.
const vtkmdiy::ReduceProxy& rp, // communication proxy
const vtkmdiy::RegularMergePartners& partners // partners of the current block
)
{ //MergeBlockFunctor
(void)partners; // Avoid unused parameter warning
const auto selfid = rp.gid();
// TODO This should be changed so that we have the ContourTree itself as the block and then the
// ContourTreeMesh would still be used for exchange. In this case we would need to compute
// the ContourTreeMesh at the beginning of the function for the current block every time
// but then we would not need to compute those meshes when we initialize vtkmdiy
// and we don't need to have the special case for rank 0.
// 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);
for (const int ingid : incoming)
{
if (ingid != selfid)
{
ContourTreeBlockData<FieldType> recvblock;
rp.dequeue(ingid, recvblock);
// Construct the two contour tree mesh by assignign the block data
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType> contourTreeMeshIn;
contourTreeMeshIn.NumVertices = recvblock.NumVertices;
contourTreeMeshIn.SortOrder = recvblock.SortOrder;
contourTreeMeshIn.SortedValues = recvblock.SortedValue;
contourTreeMeshIn.GlobalMeshIndex = recvblock.GlobalMeshIndex;
contourTreeMeshIn.Neighbours = recvblock.Neighbours;
contourTreeMeshIn.FirstNeighbour = recvblock.FirstNeighbour;
contourTreeMeshIn.MaxNeighbours = recvblock.MaxNeighbours;
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType> contourTreeMeshOut;
contourTreeMeshOut.NumVertices = block->NumVertices;
contourTreeMeshOut.SortOrder = block->SortOrder;
contourTreeMeshOut.SortedValues = block->SortedValue;
contourTreeMeshOut.GlobalMeshIndex = block->GlobalMeshIndex;
contourTreeMeshOut.Neighbours = block->Neighbours;
contourTreeMeshOut.FirstNeighbour = block->FirstNeighbour;
contourTreeMeshOut.MaxNeighbours = block->MaxNeighbours;
// Merge the two contour tree meshes
vtkm::cont::TryExecute(MergeFunctor{}, contourTreeMeshIn, contourTreeMeshOut);
// Compute the origin and size of the new block
vtkm::Id3 globalSize = block->GlobalSize;
vtkm::Id3 currBlockOrigin;
currBlockOrigin[0] = std::min(recvblock.BlockOrigin[0], block->BlockOrigin[0]);
currBlockOrigin[1] = std::min(recvblock.BlockOrigin[1], block->BlockOrigin[1]);
currBlockOrigin[2] = std::min(recvblock.BlockOrigin[2], block->BlockOrigin[2]);
vtkm::Id3 currBlockMaxIndex; // Needed only to compute the block size
currBlockMaxIndex[0] = std::max(recvblock.BlockOrigin[0] + recvblock.BlockSize[0],
block->BlockOrigin[0] + block->BlockSize[0]);
currBlockMaxIndex[1] = std::max(recvblock.BlockOrigin[1] + recvblock.BlockSize[1],
block->BlockOrigin[1] + block->BlockSize[1]);
currBlockMaxIndex[2] = std::max(recvblock.BlockOrigin[2] + recvblock.BlockSize[2],
block->BlockOrigin[2] + block->BlockSize[2]);
vtkm::Id3 currBlockSize;
currBlockSize[0] = currBlockMaxIndex[0] - currBlockOrigin[0];
currBlockSize[1] = currBlockMaxIndex[1] - currBlockOrigin[1];
currBlockSize[2] = currBlockMaxIndex[2] - currBlockOrigin[2];
// On rank 0 we compute the contour tree at the end when the merge is done, so we don't need to do it here
if (selfid == 0)
{
// Save the data from our block for the next iteration
block->NumVertices = contourTreeMeshOut.NumVertices;
block->SortOrder = contourTreeMeshOut.SortOrder;
block->SortedValue = contourTreeMeshOut.SortedValues;
block->GlobalMeshIndex = contourTreeMeshOut.GlobalMeshIndex;
block->Neighbours = contourTreeMeshOut.Neighbours;
block->FirstNeighbour = contourTreeMeshOut.FirstNeighbour;
block->MaxNeighbours = contourTreeMeshOut.MaxNeighbours;
block->BlockOrigin = currBlockOrigin;
block->BlockSize = currBlockSize;
block->GlobalSize = globalSize;
}
else // If we are a block that will continue to be merged then we need compute the contour tree here
{
// Compute the contour tree from our merged mesh
vtkm::Id currNumIterations;
vtkm::worklet::contourtree_augmented::ContourTree currContourTree;
vtkm::worklet::contourtree_augmented::IdArrayType currSortOrder;
vtkm::worklet::ContourTreeAugmented worklet;
vtkm::cont::ArrayHandle<FieldType> currField;
vtkm::Id3 maxIdx(currBlockOrigin[0] + currBlockSize[0] - 1,
currBlockOrigin[1] + currBlockSize[1] - 1,
currBlockOrigin[2] + currBlockSize[2] - 1);
auto meshBoundaryExecObj =
contourTreeMeshOut.GetMeshBoundaryExecutionObject(globalSize[0], // totalNRows
globalSize[1], // totalNCols
currBlockOrigin, // minIdx
maxIdx // maxIdx
);
worklet.Run(
contourTreeMeshOut.SortedValues, // Unused param. Provide something to keep the API happy
contourTreeMeshOut,
currContourTree,
currSortOrder,
currNumIterations,
block->ComputeRegularStructure,
meshBoundaryExecObj);
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>* newContourTreeMesh =
nullptr;
if (block->ComputeRegularStructure == 1)
{
// If we have the fully augmented contour tree
newContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>(
currContourTree.Arcs, contourTreeMeshOut);
}
else if (block->ComputeRegularStructure == 2)
{
// If we have the partially augmented (e.g., boundary augmented) contour tree
newContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>(
currContourTree.Augmentnodes, currContourTree.Augmentarcs, contourTreeMeshOut);
}
else
{
// We should not be able to get here
throw vtkm::cont::ErrorFilterExecution(
"Parallel contour tree requires at least parial boundary augmentation");
}
// Copy the data from newContourTreeMesh into block
block->NumVertices = newContourTreeMesh->NumVertices;
block->SortOrder = newContourTreeMesh->SortOrder;
block->SortedValue = newContourTreeMesh->SortedValues;
block->GlobalMeshIndex = newContourTreeMesh->GlobalMeshIndex;
block->Neighbours = newContourTreeMesh->Neighbours;
block->FirstNeighbour = newContourTreeMesh->FirstNeighbour;
block->MaxNeighbours = newContourTreeMesh->MaxNeighbours;
block->BlockOrigin = currBlockOrigin;
block->BlockSize = currBlockSize;
block->GlobalSize = globalSize;
// VTKm keeps track of the arrays for us, so we can savely delete the ContourTreeMesh
// as all data has been transferred into our data block
delete newContourTreeMesh;
}
}
}
// 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);
}
}
} //end MergeBlockFunctor
} // end namespace detail
@ -576,11 +120,12 @@ void ContourTreeAugmented::SetSpatialDecomposition(
{
if (this->MultiBlockTreeHelper)
{
delete this->MultiBlockTreeHelper;
this->MultiBlockTreeHelper = nullptr;
this->MultiBlockTreeHelper.reset();
}
this->MultiBlockTreeHelper = new detail::MultiBlockContourTreeHelper(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
this->MultiBlockTreeHelper =
std::unique_ptr<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>(
new vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes));
}
const vtkm::worklet::contourtree_augmented::ContourTree& ContourTreeAugmented::GetContourTree()
@ -623,7 +168,7 @@ vtkm::cont::DataSet ContourTreeAugmented::DoExecute(
vtkm::Id nSlices = 1;
const auto& cells = input.GetCellSet();
vtkm::filter::ApplyPolicyCellSet(cells, policy, *this)
.CastAndCall(GetRowsColsSlices(), nRows, nCols, nSlices);
.CastAndCall(vtkm::worklet::contourtree_augmented::GetRowsColsSlices(), nRows, nCols, nSlices);
// 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;
@ -677,7 +222,7 @@ vtkm::cont::DataSet ContourTreeAugmented::DoExecute(
}
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
std::endl
<< " "
<< std::setw(38)
@ -742,7 +287,7 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(
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::filter::detail::ContourTreeBlockData<T>*> localDataBlocks;
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()));
@ -764,10 +309,12 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(
//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().template AsVirtual<T>(), fieldData);
auto currContourTreeMesh =
vtkm::filter::detail::MultiBlockContourTreeHelper::ComputeLocalContourTreeMesh<T>(
localBlocksOriginPortal.Get(static_cast<vtkm::Id>(bi)),
localBlocksSizesPortal.Get(static_cast<vtkm::Id>(bi)),
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],
@ -775,7 +322,7 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(
compRegularStruct);
localContourTreeMeshes[bi] = currContourTreeMesh;
// create the local data block structure
localDataBlocks[bi] = new vtkm::filter::detail::ContourTreeBlockData<T>();
localDataBlocks[bi] = new vtkm::worklet::contourtree_distributed::ContourTreeBlockData<T>();
localDataBlocks[bi]->NumVertices = currContourTreeMesh->NumVertices;
localDataBlocks[bi]->SortOrder = currContourTreeMesh->SortOrder;
localDataBlocks[bi]->SortedValue = currContourTreeMesh->SortedValues;
@ -799,7 +346,7 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(
);
// Compute the gids for our local blocks
const detail::SpatialDecomposition& spatialDecomp =
const vtkm::worklet::contourtree_distributed::SpatialDecomposition& spatialDecomp =
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition;
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
std::vector<vtkm::Id> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
@ -853,7 +400,8 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(
true // contiguous: true=distance doubling , false=distnace halving TODO check this value
);
// reduction
vtkmdiy::reduce(master, assigner, partners, &detail::MergeBlockFunctor<T>);
vtkmdiy::reduce(
master, assigner, partners, &vtkm::worklet::contourtree_distributed::MergeBlockFunctor<T>);
comm.barrier(); // Be safe!
@ -957,9 +505,8 @@ inline VTKM_CONT void ContourTreeAugmented::PostExecute(
metaData,
policy);
delete this->MultiBlockTreeHelper;
this->MultiBlockTreeHelper = nullptr;
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
this->MultiBlockTreeHelper.reset();
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
std::endl
<< " "
<< std::setw(38)

@ -0,0 +1,172 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_ContourTreeUniformDistributed_h
#define vtk_m_filter_ContourTreeUniformDistributed_h
#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/filter/FilterCell.h>
#include <memory>
namespace vtkm
{
namespace filter
{
/// \brief Construct the Contour Tree for a 2D or 3D regular mesh
///
/// This filter implements the parallel peak pruning algorithm. In contrast to
/// the ContourTreeUniform filter, this filter is optimized to allow for the
/// computation of the augmented contour tree, i.e., the contour tree including
/// all regular mesh vertices. Augmentation with regular vertices is used in
/// practice to compute statistics (e.g., volume), to segment the input mesh,
/// facilitate iso-value selection, enable localization of all verticies of a
/// mesh in the tree among others.
///
/// In addition to single-block computation, the filter also supports multi-block
/// regular grids. The blocks are processed in parallel using DIY and then the
/// tree are merged progressively using a binary-reduction scheme to compute the
/// final contour tree. I.e., in the multi-block context, the final tree is
/// constructed on rank 0.
class ContourTreeUniformDistributed : public vtkm::filter::FilterCell<ContourTreeUniformDistributed>
{
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
/// with respect to blocksPerDim
/// @param[in] localBlockOrigins Array with the (x,y,z) origin (with regard to mesh index) of each
/// local data block
/// @param[in] localBlockSizes Array with the sizes (i.e., extends in number of mesh points) of each
/// local data block
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);
/// 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);
//@{
/// when operating on vtkm::cont::MultiBlock we want to
/// do processing across ranks as well. Just adding pre/post handles
/// for the same does the trick.
template <typename DerivedPolicy>
VTKM_CONT void PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
template <typename DerivedPolicy>
VTKM_CONT void PostExecute(const vtkm::cont::PartitionedDataSet& input,
vtkm::cont::PartitionedDataSet& output,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
///
/// Internal helper function that implements the actual functionality of PostExecute
///
/// In the case we operate on vtkm::cont::MultiBlock we need to merge the trees
/// computed on the block to compute the final contour tree.
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT void 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);
//@}
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;
/// 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
} // namespace vtkm
#include <vtkm/filter/ContourTreeUniformDistributed.hxx>
#endif // vtk_m_filter_ContourTreeUniformAugmented_h

@ -0,0 +1,491 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_ContourTreeUniformDistributed_hxx
#define vtk_m_filter_ContourTreeUniformDistributed_hxx
// vtkm includes
#include <vtkm/cont/Timer.h>
// single-node augmented contour tree includes
#include <vtkm/filter/ContourTreeUniformDistributed.h>
#include <vtkm/worklet/ContourTreeUniformAugmented.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/ContourTreeMesh.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/SpatialDecomposition.h>
// DIY includes
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/Configure.h>
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
namespace vtkm
{
namespace filter
{
namespace contourtree_distributed_detail
{
//----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
struct PostExecuteCaller
{
template <typename T, typename S, typename DerivedPolicy>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, S>&,
ContourTreeUniformDistributed* self,
const vtkm::cont::PartitionedDataSet& input,
vtkm::cont::PartitionedDataSet& output,
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<DerivedPolicy> policy) const
{
vtkm::cont::ArrayHandle<T, S> dummy;
self->DoPostExecute(input, output, fieldMeta, dummy, policy);
}
};
} // end namespace contourtree_distributed_detail
//-----------------------------------------------------------------------------
ContourTreeUniformDistributed::ContourTreeUniformDistributed(bool useMarchingCubes)
: vtkm::filter::FilterCell<ContourTreeUniformDistributed>()
, UseMarchingCubes(useMarchingCubes)
, MultiBlockTreeHelper(nullptr)
{
this->SetOutputFieldName("resultData");
}
void ContourTreeUniformDistributed::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)
{
if (this->MultiBlockTreeHelper)
{
this->MultiBlockTreeHelper.reset();
}
this->MultiBlockTreeHelper =
std::unique_ptr<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>(
new vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes));
}
//-----------------------------------------------------------------------------
template <typename T, typename StorageType, typename DerivedPolicy>
vtkm::cont::DataSet ContourTreeUniformDistributed::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::Timer timer;
timer.Start();
// Check that the field is Ok
if (fieldMeta.IsPointField() == false)
{
throw vtkm::cont::ErrorFilterExecution("Point field expected.");
}
// Use the GetRowsColsSlices struct defined in the header to collect the nRows, nCols, and nSlices information
vtkm::worklet::ContourTreeAugmented worklet;
vtkm::Id nRows;
vtkm::Id nCols;
vtkm::Id nSlices = 1;
const auto& cells = input.GetCellSet();
vtkm::filter::ApplyPolicyCellSet(cells, policy, *this)
.CastAndCall(vtkm::worklet::contourtree_augmented::GetRowsColsSlices(), nRows, nCols, nSlices);
// 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;
// Run the worklet
worklet.Run(field,
MultiBlockTreeHelper ? MultiBlockTreeHelper->LocalContourTrees[blockIndex]
: this->ContourTreeData,
MultiBlockTreeHelper ? MultiBlockTreeHelper->LocalSortOrders[blockIndex]
: this->MeshSortOrder,
this->NumIterations,
nRows,
nCols,
nSlices,
this->UseMarchingCubes,
compRegularStruct);
// 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;
}
}
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
std::endl
<< " "
<< std::setw(38)
<< std::left
<< "Contour Tree Filter DoExecute"
<< ": "
<< timer.GetElapsedTime()
<< " seconds");
// 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
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void ContourTreeUniformDistributed::PreExecute(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
if (this->MultiBlockTreeHelper)
{
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");
}
}
}
//-----------------------------------------------------------------------------
template <typename T, 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)
{
(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;
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;
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;
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
// Create the vtkmdiy master
vtkmdiy::Master master(comm,
1, // Use 1 thread, VTK-M will do the treading
-1 // All block in memory
);
// Compute the gids for our local blocks
const vtkm::worklet::contourtree_distributed::SpatialDecomposition& spatialDecomp =
this->MultiBlockTreeHelper->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++)
{
std::vector<int> tempCoords; // DivisionsVector type in DIY
std::vector<int> tempDivisions; // DivisionsVector type in DIY
tempCoords.resize(static_cast<size_t>(spatialDecomp.NumberOfDimensions()));
tempDivisions.resize(static_cast<size_t>(spatialDecomp.NumberOfDimensions()));
auto currentCoords = localBlockIndicesPortal.Get(bi);
for (std::size_t di = 0; di < static_cast<size_t>(spatialDecomp.NumberOfDimensions()); di++)
{
tempCoords[di] = static_cast<int>(currentCoords[static_cast<vtkm::IdComponent>(di)]);
tempDivisions[di] =
static_cast<int>(spatialDecomp.BlocksPerDimension[static_cast<vtkm::IdComponent>(di)]);
}
vtkmdiyLocalBlockGids[static_cast<size_t>(bi)] =
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>::coords_to_gid(tempCoords, tempDivisions);
}
// Add my local blocks to the vtkmdiy master.
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
{
master.add(static_cast<int>(vtkmdiyLocalBlockGids[bi]), // block id
localDataBlocks[bi],
localLinks[bi]);
}
// Define the decomposition of the domain into regular blocks
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds> decomposer(
static_cast<int>(spatialDecomp.NumberOfDimensions()), // number of dims
spatialDecomp.GetVTKmDIYBounds(),
static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
// Define which blocks live on which rank so that vtkmdiy can manage them
vtkmdiy::DynamicAssigner assigner(
comm, static_cast<int>(size), static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
assigner.set_rank(static_cast<int>(rank),
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
vtkmdiy::fix_links(master, assigner);
// partners for merge over regular block grid
vtkmdiy::RegularMergePartners 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>);
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;
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[0],
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize[1],
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);
// 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;
// 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];
// Free allocated temporary pointers
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
{
delete localContourTreeMeshes[bi];
delete localDataBlocks[bi];
// delete localLinks[bi];
}
}
localContourTreeMeshes.clear();
localDataBlocks.clear();
localLinks.clear();
}
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void ContourTreeUniformDistributed::PostExecute(
const vtkm::cont::PartitionedDataSet& input,
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
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");
}
}
} // namespace filter
} // namespace vtkm::filter
#endif

@ -124,6 +124,7 @@ add_subdirectory(connectivities)
add_subdirectory(contour)
add_subdirectory(contourtree)
add_subdirectory(contourtree_augmented)
add_subdirectory(contourtree_distributed)
add_subdirectory(cosmotools)
add_subdirectory(gradient)
add_subdirectory(histogram)

@ -76,7 +76,9 @@
#include <vtkm/worklet/contourtree_augmented/Mesh_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/ContourTreeMesh.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshBoundary.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundary2D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundary3D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundaryContourTreeMesh.h>
namespace vtkm
{
@ -352,14 +354,14 @@ private:
timer.Start();
// Collect the output data
nIterations = treeMaker.NumIterations;
nIterations = treeMaker.ContourTreeResult.NumIterations;
sortOrder = mesh.SortOrder;
// ProcessContourTree::CollectSortedSuperarcs<DeviceAdapter>(contourTree, mesh.SortOrder, saddlePeak);
// contourTree.SortedArcPrint(mesh.SortOrder);
// contourTree.PrintDotSuperStructure();
// Log the collected timing results in one coherent log entry
VTKM_LOG_S(vtkm::cont::LogLevel::Info, timingsStream.str());
VTKM_LOG_S(vtkm::cont::LogLevel::Perf, timingsStream.str());
}
};

@ -148,11 +148,14 @@ public:
// because not all Hyperarcs lead to hypernodes
IdArrayType Hyperarcs;
// counter for the number of iterations it took to construct the tree
// this is also used for hypersweep computations
vtkm::Id NumIterations;
// vectors tracking the segments used in each iteration of the hypersweep
IdArrayType FirstSupernodePerIteration;
IdArrayType FirstHypernodePerIteration;
// THIS ONE HAS BEEN DELETED BECAUSE IT'S THE SAME AS THE HYPERNODE ID
// ALTHOUGH THIS IS NOT NECESSARY, IT'S THE RESULT OF THE CONSTRUCTION
// vector to find the first child superarc
// IdArrayType FirstSuperchild;
// ROUTINES
@ -216,6 +219,11 @@ inline void ContourTree::PrintContent() const
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);
}
void ContourTree::DebugPrint(const char* message, const char* fileName, long lineNum) const

@ -71,6 +71,7 @@
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeHyperAndSuperStructure_HypernodesSetFirstSuperchild.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeHyperAndSuperStructure_PermuteArcs.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeHyperAndSuperStructure_ResetHyperparentsId.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeHyperAndSuperStructure_SetNewHypernodesAndArcs.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeRegularStructure_LocateSuperarcs.h>
#include <vtkm/worklet/contourtree_augmented/contourtreemaker/ComputeRegularStructure_SetArcs.h>
@ -132,9 +133,6 @@ public:
// vector for the active set of supernodes
IdArrayType ActiveSupernodes;
// counter for the number of iterations it took
vtkm::Id NumIterations;
// constructor does the real work does the real work but mostly, it just calls the following two routines
ContourTreeMaker(ContourTree& theContourTree, MergeTree& joinTree, MergeTree& splitTree);
@ -186,7 +184,6 @@ ContourTreeMaker::ContourTreeMaker(ContourTree& contourTree,
, AugmentedJoinSuperarcs()
, AugmentedSplitSuperarcs()
, ActiveSupernodes()
, NumIterations(0)
{ // constructor
} //MakeContourTree()
@ -198,7 +195,7 @@ void ContourTreeMaker::ComputeHyperAndSuperStructure()
AugmentMergeTrees();
// track how many iterations it takes
this->NumIterations = 0;
this->ContourTreeResult.NumIterations = 0;
// loop until no arcs remaining to be found
// tree can end with either 0 or 1 vertices unprocessed
@ -210,7 +207,7 @@ void ContourTreeMaker::ComputeHyperAndSuperStructure()
FindDegrees();
// alternate iterations between upper & lower
if (this->NumIterations % 2 == 0)
if (this->ContourTreeResult.NumIterations % 2 == 0)
TransferLeafChains(true);
else
TransferLeafChains(false);
@ -219,7 +216,7 @@ void ContourTreeMaker::ComputeHyperAndSuperStructure()
CompressTrees();
// compress the active list of supernodes
CompressActiveSupernodes();
this->NumIterations++;
this->ContourTreeResult.NumIterations++;
} // loop until no active vertices remaining
// test for final edges meeting
@ -231,8 +228,8 @@ void ContourTreeMaker::ComputeHyperAndSuperStructure()
this->ContourTreeResult.Hyperarcs.WritePortal().Set(superID,
static_cast<vtkm::Id>(NO_SUCH_ELEMENT));
this->ContourTreeResult.Hyperparents.WritePortal().Set(superID, superID);
this->ContourTreeResult.WhenTransferred.WritePortal().Set(superID,
this->NumIterations | IS_HYPERNODE);
this->ContourTreeResult.WhenTransferred.WritePortal().Set(
superID, this->ContourTreeResult.NumIterations | IS_HYPERNODE);
} // meet at a vertex
DebugPrint("Contour Tree Constructed. Now Swizzling", __FILE__, __LINE__);
@ -385,6 +382,66 @@ void ContourTreeMaker::ComputeHyperAndSuperStructure()
resetHyperparentsIdWorklet;
this->Invoke(resetHyperparentsIdWorklet, superSortIndex, this->ContourTreeResult.Hyperparents);
// set up the array which tracks which supernodes to deal with on which iteration:
// it's plus 2 because there's an "extra" iteration for the root
// and it's useful to store the size as one beyond that
// initalize with 0's to be safe
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleConstant<vtkm::Id>(0, this->ContourTreeResult.NumIterations + 2),
this->ContourTreeResult.FirstSupernodePerIteration);
{
contourtree_maker_inc_ns::ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet
setFirstSupernodePerIterationWorklet;
auto tempSupernodesIndex =
vtkm::cont::ArrayHandleIndex(this->ContourTreeResult.Supernodes.GetNumberOfValues());
this->Invoke(setFirstSupernodePerIterationWorklet,
tempSupernodesIndex, // loopindex
this->ContourTreeResult.WhenTransferred, // input
this->ContourTreeResult.FirstSupernodePerIteration // output
);
}
// TODO The following loop should be safe in parallel since there should never be two zeros in sequence, i.e., the next
// entry after a zero will always be valid, regardless of execution order. Because this is safe if could be implemented
// as a worklet. The number of iterations in the loop is small, so it may not be necessary for performance.
auto firstSupernodePerIterationPortal =
this->ContourTreeResult.FirstSupernodePerIteration.WritePortal();
for (vtkm::Id iteration = 1; iteration < this->ContourTreeResult.NumIterations; ++iteration)
{
if (firstSupernodePerIterationPortal.Get(iteration) == 0)
{
firstSupernodePerIterationPortal.Set(iteration,
firstSupernodePerIterationPortal.Get(iteration + 1));
}
}
// set the sentinels at the end of the array
firstSupernodePerIterationPortal.Set(this->ContourTreeResult.NumIterations,
this->ContourTreeResult.Supernodes.GetNumberOfValues() - 1);
firstSupernodePerIterationPortal.Set(this->ContourTreeResult.NumIterations + 1,
this->ContourTreeResult.Supernodes.GetNumberOfValues());
// now use that array to construct a similar array for hypernodes: it's plus 2 because there's an "extra" iteration for the root
// and it's useful to store the size as one beyond that
this->ContourTreeResult.FirstHypernodePerIteration.Allocate(
this->ContourTreeResult.NumIterations + 2);
{
// permute the ContourTree.Hyperpartens by the ContourTreeFirstSupernodePerIteration
auto tempContourTreeHyperparentsPermuted = vtkm::cont::make_ArrayHandlePermutation(
this->ContourTreeResult.FirstSupernodePerIteration, this->ContourTreeResult.Hyperparents);
vtkm::cont::Algorithm::CopySubRange(tempContourTreeHyperparentsPermuted,
0, // start index
this->ContourTreeResult.NumIterations, // stop index
this->ContourTreeResult.FirstHypernodePerIteration // target
);
}
this->ContourTreeResult.FirstHypernodePerIteration.WritePortal().Set(
this->ContourTreeResult.NumIterations,
this->ContourTreeResult.Hypernodes.GetNumberOfValues() - 1);
this->ContourTreeResult.FirstHypernodePerIteration.WritePortal().Set(
this->ContourTreeResult.NumIterations + 1,
this->ContourTreeResult.Hypernodes.GetNumberOfValues());
DebugPrint("Contour Tree Super Structure Constructed", __FILE__, __LINE__);
} // ComputeHyperAndSuperStructure()
@ -829,13 +886,13 @@ void ContourTreeMaker::TransferLeafChains(bool isJoin)
// loop through the active vertices
details::LeafChainsToContourTree task(this->NumIterations, // (input)
isJoin, // (input)
outdegree, // (input)
indegree, // (input)
outbound, // (input)
inbound, // (input)
inwards); // (input)
details::LeafChainsToContourTree task(this->ContourTreeResult.NumIterations, // (input)
isJoin, // (input)
outdegree, // (input)
indegree, // (input)
outbound, // (input)
inbound, // (input)
inwards); // (input)
vtkm::cont::TryExecute(task,
this->ActiveSupernodes, // (input)
this->ContourTreeResult.Hyperparents, // (output)
@ -1010,7 +1067,7 @@ void ContourTreeMaker::DebugPrint(const char* message, const char* fileName, lon
std::cout << std::left << std::string(message) << std::endl;
std::cout << "Contour Tree Maker Contains: " << std::endl;
std::cout << "------------------------------------------------------" << std::endl;
std::cout << "NumIterations: " << this->NumIterations << std::endl;
std::cout << "NumIterations: " << this->ContourTreeResult.NumIterations << std::endl;
PrintHeader(this->Updegree.GetNumberOfValues());
PrintIndices("Updegree", this->Updegree);

@ -241,7 +241,7 @@ inline void MergeTree::DebugPrintTree(const char* message,
for (vtkm::Id entry = 0; entry < mesh.NumVertices; entry++)
{
vtkm::Id sortIndex = mesh.SortIndices.ReadPortal().Get(entry);
vtkm::Id arc = this->arcs.ReadPortal().Get(sortIndex);
vtkm::Id arc = this->Arcs.ReadPortal().Get(sortIndex);
if (NoSuchElement(arc))
{
std::cout << "-1" << std::endl;
@ -259,7 +259,7 @@ inline void MergeTree::DebugPrintTree(const char* message,
}
else if (mesh.NumDims == 3)
{
if ((entry % (mesh.NumColumns * mesh.NumRows)) == (mesh.nCols * mesh.NumRows - 1))
if ((entry % (mesh.NumColumns * mesh.NumRows)) == (mesh.NumColumns * mesh.NumRows - 1))
{
std::cout << std::endl;
}

@ -82,7 +82,6 @@
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/IdRelabler.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/SimulatedSimplicityComperator.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/SortIndices.h>

@ -83,73 +83,76 @@ constexpr int PREFIX_WIDTH = 24;
template <typename T, typename StorageType>
void PrintValues(std::string label,
const vtkm::cont::ArrayHandle<T, StorageType>& dVec,
vtkm::Id nValues = -1);
vtkm::Id nValues = -1,
std::ostream& outStream = std::cout);
void PrintIndices(std::string label,
const vtkm::cont::ArrayHandle<vtkm::Id>& iVec,
vtkm::Id nIndices = -1);
vtkm::Id nIndices = -1,
std::ostream& outStream = std::cout);
template <typename T, typename StorageType>
void PrintSortedValues(std::string label,
const vtkm::cont::ArrayHandle<T, StorageType>& dVec,
IdArrayType& sortVec,
vtkm::Id nValues = -1);
vtkm::Id nValues = -1,
std::ostream& outStream = std::cout);
// base routines for printing label & prefix bars
inline void PrintLabel(std::string label)
inline void PrintLabel(std::string label, std::ostream& outStream = std::cout)
{ // PrintLabel()
// print out the front end
std::cout << std::setw(PREFIX_WIDTH) << std::left << label;
outStream << std::setw(PREFIX_WIDTH) << std::left << label;
// print out the vertical line
std::cout << std::right << "|";
outStream << std::right << "|";
} // PrintLabel()
inline void PrintSeparatingBar(vtkm::Id howMany)
inline void PrintSeparatingBar(vtkm::Id howMany, std::ostream& outStream = std::cout)
{ // PrintSeparatingBar()
// print out the front end
std::cout << std::setw(PREFIX_WIDTH) << std::setfill('-') << "";
outStream << std::setw(PREFIX_WIDTH) << std::setfill('-') << "";
// now the + at the vertical line
std::cout << "+";
outStream << "+";
// now print out the tail end - fixed number of spaces per entry
for (vtkm::Id block = 0; block < howMany; block++)
{
std::cout << std::setw(PRINT_WIDTH) << std::setfill('-') << "";
outStream << std::setw(PRINT_WIDTH) << std::setfill('-') << "";
}
// now the std::endl, resetting the fill character
std::cout << std::setfill(' ') << std::endl;
outStream << std::setfill(' ') << std::endl;
} // PrintSeparatingBar()
// routine to print out a single value
template <typename T>
inline void PrintDataType(T value)
inline void PrintDataType(T value, std::ostream& outStream = std::cout)
{ // PrintDataType
std::cout << std::setw(PRINT_WIDTH) << value;
outStream << std::setw(PRINT_WIDTH) << value;
} // PrintDataType
// routine to print out a single index
inline void PrintIndexType(vtkm::Id index)
inline void PrintIndexType(vtkm::Id index, std::ostream& outStream = std::cout)
{ // PrintIndexType
std::cout << std::setw(PRINT_WIDTH - 6) << MaskedIndex(index) << " " << FlagString(index);
outStream << std::setw(PRINT_WIDTH - 6) << MaskedIndex(index) << " " << FlagString(index);
} // PrintIndexType
// header line
inline void PrintHeader(vtkm::Id howMany)
inline void PrintHeader(vtkm::Id howMany, std::ostream& outStream = std::cout)
{ // PrintHeader()
// print out a separating bar
PrintSeparatingBar(howMany);
PrintSeparatingBar(howMany, outStream);
// print out a label
PrintLabel("ID");
PrintLabel("ID", outStream);
// print out the ID numbers
for (vtkm::Id entry = 0; entry < howMany; entry++)
{
PrintIndexType(entry);
PrintIndexType(entry, outStream);
}
// and an std::endl
std::cout << std::endl;
outStream << std::endl;
// print out another separating bar
PrintSeparatingBar(howMany);
PrintSeparatingBar(howMany, outStream);
} // PrintHeader()
@ -157,7 +160,8 @@ inline void PrintHeader(vtkm::Id howMany)
template <typename T, typename StorageType>
inline void PrintValues(std::string label,
const vtkm::cont::ArrayHandle<T, StorageType>& dVec,
vtkm::Id nValues)
vtkm::Id nValues,
std::ostream& outStream)
{ // PrintValues()
// -1 means full size
if (nValues == -1)
@ -166,16 +170,16 @@ inline void PrintValues(std::string label,
}
// print the label
PrintLabel(label);
PrintLabel(label, outStream);
// now print the data
auto portal = dVec.ReadPortal();
for (vtkm::Id entry = 0; entry < nValues; entry++)
{
PrintDataType(portal.Get(entry));
PrintDataType(portal.Get(entry), outStream);
}
// and an std::endl
std::cout << std::endl;
outStream << std::endl;
} // PrintValues()
@ -184,7 +188,8 @@ template <typename T, typename StorageType>
inline void PrintSortedValues(std::string label,
const vtkm::cont::ArrayHandle<T, StorageType>& dVec,
IdArrayType& sortVec,
vtkm::Id nValues)
vtkm::Id nValues,
std::ostream& outStream)
{ // PrintSortedValues()
// -1 means full size
if (nValues == -1)
@ -193,24 +198,25 @@ inline void PrintSortedValues(std::string label,
}
// print the label
PrintLabel(label);
PrintLabel(label, outStream);
// now print the data
auto dportal = dVec.ReadPortal();
auto sortPortal = sortVec.ReadPortal();
for (vtkm::Id entry = 0; entry < nValues; entry++)
{
PrintDataType(dportal.Get(sortPortal.Get(entry)));
PrintDataType(dportal.Get(sortPortal.Get(entry)), outStream);
}
// and an std::endl
std::cout << std::endl;
outStream << std::endl;
} // PrintSortedValues()
// routine for printing index arrays
inline void PrintIndices(std::string label,
const vtkm::cont::ArrayHandle<vtkm::Id>& iVec,
vtkm::Id nIndices)
vtkm::Id nIndices,
std::ostream& outStream)
{ // PrintIndices()
// -1 means full size
if (nIndices == -1)
@ -219,53 +225,55 @@ inline void PrintIndices(std::string label,
}
// print the label
PrintLabel(label);
PrintLabel(label, outStream);
auto portal = iVec.ReadPortal();
for (vtkm::Id entry = 0; entry < nIndices; entry++)
PrintIndexType(portal.Get(entry));
PrintIndexType(portal.Get(entry), outStream);
// and the std::endl
std::cout << std::endl;
outStream << std::endl;
} // PrintIndices()
template <typename T, typename StorageType>
inline void PrintLabelledDataBlock(std::string label,
const vtkm::cont::ArrayHandle<T, StorageType>& dVec,
vtkm::Id nColumns)
vtkm::Id nColumns,
std::ostream& outStream = std::cout)
{ // PrintLabelledDataBlock()
// start with a header
PrintHeader(nColumns);
PrintHeader(nColumns, outStream);
// loop control variable
vtkm::Id entry = 0;
// per row
auto portal = dVec.ReadPortal();
for (vtkm::Id row = 0; entry < portal.GetNumberOfValues(); row++)
{ // per row
PrintLabel(label + "[" + std::to_string(row) + "]");
PrintLabel(label + "[" + std::to_string(row) + "]", outStream);
// now print the data
for (vtkm::Id col = 0; col < nColumns; col++, entry++)
{
PrintDataType(portal.Get(entry));
PrintDataType(portal.Get(entry), outStream);
}
std::cout << std::endl;
outStream << std::endl;
} // per row
// and a final std::endl
std::cout << std::endl;
outStream << std::endl;
} // 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)
inline void PrintEdgePairArray(const EdgePairArray& edgePairArray,
std::ostream& outStream = std::cout)
{ // PrintEdgePairArray()
// now print them out
auto edgePairArrayConstPortal = edgePairArray.ReadPortal();
for (vtkm::Id superarc = 0; superarc < edgePairArray.GetNumberOfValues(); superarc++)
{ // per superarc
std::cout << std::right << std::setw(PRINT_WIDTH)
outStream << std::right << std::setw(PRINT_WIDTH)
<< edgePairArrayConstPortal.Get(superarc).first << " ";
std::cout << std::right << std::setw(PRINT_WIDTH)
outStream << std::right << std::setw(PRINT_WIDTH)
<< edgePairArrayConstPortal.Get(superarc).second << std::endl;
} // per superarc
} // PrintEdgePairArray()

@ -262,7 +262,13 @@ public:
hyperarcDependentWeight);
// set up the array which tracks which supernodes to deal with on which iteration
IdArrayType firstSupernodePerIteration;
auto firstSupernodePerIterationPortal = contourTree.FirstSupernodePerIteration.ReadPortal();
auto firstHypernodePerIterationPortal = contourTree.FirstHypernodePerIteration.ReadPortal();
auto supernodeTransferWeightPortal = supernodeTransferWeight.WritePortal();
auto superarcDependentWeightPortal = superarcDependentWeight.WritePortal();
auto hyperarcDependentWeightPortal = hyperarcDependentWeight.WritePortal();
/*
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleConstant<vtkm::Id>(0, nIterations + 1),
firstSupernodePerIteration);
auto firstSupernodePerIterationPortal = firstSupernodePerIteration.WritePortal();
@ -298,6 +304,7 @@ public:
firstHypernodePerIterationPortal.Set(
iteration, hyperparentsPortal.Get(firstSupernodePerIterationPortal.Get(iteration)));
firstHypernodePerIterationPortal.Set(nIterations, contourTree.Hypernodes.GetNumberOfValues());
*/
// now iterate, propagating weights inwards
for (vtkm::Id iteration = 0; iteration < nIterations; iteration++)

@ -56,6 +56,7 @@
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CellSetStructured.h>
namespace vtkm
{
@ -73,6 +74,7 @@ constexpr vtkm::Id IS_HYPERNODE = std::numeric_limits<vtkm::Id>::max() / 8 + 1;
constexpr vtkm::Id IS_ASCENDING = std::numeric_limits<vtkm::Id>::max() / 16 + 1; //0x08000000 || 0x0800000000000000
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
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
@ -147,6 +149,53 @@ inline std::string FlagString(vtkm::Id flaggedIndex)
} // FlagString()
///
/// Helper struct to collect sizing information from a dataset.
/// The struct is used in the contour tree filter implementation
/// to determine the rows, cols, slices parameters from the
/// datasets so we can call the contour tree worklet properly.
///
struct GetRowsColsSlices
{
//@{
/// Get the number of rows, cols, and slices of a vtkm::cont::CellSetStructured
/// @param[in] cells The input vtkm::cont::CellSetStructured
/// @param[out] nRows Number of rows (x) in the cell set
/// @param[out[ nCols Number of columns (y) in the cell set
/// @param[out] nSlices Number of slices (z) in the cell set
void operator()(const vtkm::cont::CellSetStructured<2>& cells,
vtkm::Id& nRows,
vtkm::Id& nCols,
vtkm::Id& nSlices) const
{
vtkm::Id2 pointDimensions = cells.GetPointDimensions();
nRows = pointDimensions[0];
nCols = pointDimensions[1];
nSlices = 1;
}
void operator()(const vtkm::cont::CellSetStructured<3>& cells,
vtkm::Id& nRows,
vtkm::Id& nCols,
vtkm::Id& nSlices) const
{
vtkm::Id3 pointDimensions = cells.GetPointDimensions();
nRows = pointDimensions[0];
nCols = pointDimensions[1];
nSlices = pointDimensions[2];
}
//@}
/// Raise ErrorBadValue if the input cell set is not a vtkm::cont::CellSetStructured<2> or <3>
template <typename T>
void operator()(const T& cells, vtkm::Id& nRows, vtkm::Id& nCols, vtkm::Id& nSlices) const
{
(void)nRows;
(void)nCols;
(void)nSlices;
(void)cells;
throw vtkm::cont::ErrorBadValue("Expected 2D or 3D structured cell cet! ");
}
};
} // namespace contourtree_augmented
} // worklet

@ -16,6 +16,7 @@ set(headers
ComputeHyperAndSuperStructure_PermuteArcs.h
ComputeHyperAndSuperStructure_ResetHyperparentsId.h
ComputeHyperAndSuperStructure_SetNewHypernodesAndArcs.h
ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet.h
ComputeRegularStructure_LocateSuperarcs.h
ComputeRegularStructure_SetArcs.h
ContourTreeSuperNodeComparator.h

@ -0,0 +1,128 @@
//============================================================================
// 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_augmented_contourtree_maker_inc_compute_hyper_and_super_structure_set_first_supernode_per_iteration_worklet_h
#define vtk_m_worklet_contourtree_augmented_contourtree_maker_inc_compute_hyper_and_super_structure_set_first_supernode_per_iteration_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
namespace contourtree_maker_inc
{
// Worklet for settubg the super/hyperarcs fromm the permuted super/hyperarcs vector
class ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet
: public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn supernodeIndex, // (input) active super/hyperarcs
WholeArrayIn whenTransferred, // (input)
WholeArrayOut firstSupernodePerIteration); // (output)
typedef void ExecutionSignature(_1, _2, _3);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& supernode,
const InFieldPortalType& whenTransferredPortal,
const OutFieldPortalType& firstSupernodePerIterationPortal) const
{
// per supernode
vtkm::Id when =
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(supernode));
if (supernode == 0)
{ // zeroth supernode
firstSupernodePerIterationPortal.Set(when, supernode);
} // zeroth supernode
else
{
vtkm::Id prevWhen =
vtkm::worklet::contourtree_augmented::MaskedIndex(whenTransferredPortal.Get(supernode - 1));
if (when != prevWhen)
{ // non-matching supernode
firstSupernodePerIterationPortal.Set(when, supernode);
} // non-matching supernode
}
// In serial this worklet implements the following operation
/*
for (indexType supernode = 0; supernode < contourTree.supernodes.size(); supernode++)
{ // per supernode
indexType when = maskedIndex(contourTree.whenTransferred[supernode]);
if (supernode == 0)
{ // zeroth supernode
contourTree.firstSupernodePerIteration[when] = supernode;
} // zeroth supernode
else if (when != maskedIndex(contourTree.whenTransferred[supernode-1]))
{ // non-matching supernode
contourTree.firstSupernodePerIteration[when] = supernode;
} // non-matching supernode
} // per supernode
*/
}
}; // ComputeHyperAndSuperStructure_SetFirstSupernodePerIterationWorklet
} // namespace contourtree_maker_inc
} // namespace contourtree_augmented
} // namespace worklet
} // namespace vtkm
#endif

@ -12,7 +12,7 @@ set(headers
MeshStructure3D.h
SimulatedSimplicityComperator.h
SortIndices.h
IdRelabler.h
IdRelabeler.h
)
#-----------------------------------------------------------------------------

@ -60,8 +60,8 @@
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_worklet_contourtree_ppp2_contourtree_mesh_inc_id_relabler_h
#define vtk_m_worklet_contourtree_ppp2_contourtree_mesh_inc_id_relabler_h
#ifndef vtk_m_worklet_contourtree_ppp2_contourtree_mesh_inc_id_relabeler_h
#define vtk_m_worklet_contourtree_ppp2_contourtree_mesh_inc_id_relabeler_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
@ -76,11 +76,11 @@ namespace mesh_dem
{
class IdRelabler
class IdRelabeler
{
public:
VTKM_EXEC_CONT
IdRelabler()
IdRelabeler()
: InputStartRow(0)
, InputStartCol(0)
, InputStartSlice(0)
@ -92,13 +92,13 @@ public:
}
VTKM_EXEC_CONT
IdRelabler(vtkm::Id iSR,
vtkm::Id iSC,
vtkm::Id iSS,
vtkm::Id iNR,
vtkm::Id iNC,
vtkm::Id oNR,
vtkm::Id oNC)
IdRelabeler(vtkm::Id iSR,
vtkm::Id iSC,
vtkm::Id iSS,
vtkm::Id iNR,
vtkm::Id iNC,
vtkm::Id oNR,
vtkm::Id oNC)
: InputStartRow(iSR)
, InputStartCol(iSC)
, InputStartSlice(iSS)

@ -16,11 +16,11 @@ set(headers
MeshStructureFreudenthal3D.h
MeshStructureMarchingCubes.h
MeshStructureContourTreeMesh.h
MeshBoundary.h
)
#----------------------------------------------------------------------------
add_subdirectory(contourtreemesh)
add_subdirectory(mesh_boundary)
#-----------------------------------------------------------------------------
vtkm_declare_headers(${headers})

@ -74,7 +74,6 @@
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/contourtree_augmented/ArrayTransforms.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshBoundary.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshStructureContourTreeMesh.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/contourtreemesh/ArcComparator.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/contourtreemesh/CombinedOtherStartIndexNNeighboursWorklet.h>
@ -89,6 +88,9 @@
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/contourtreemesh/ReplaceArcNumWithToVertexWorklet.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/contourtreemesh/SubtractAssignWorklet.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/contourtreemesh/UpdateCombinedNeighboursWorklet.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/ComputeMeshBoundaryContourTreeMesh.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundaryContourTreeMesh.h>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h> // TODO remove should not be needed
@ -209,6 +211,11 @@ public:
vtkm::Id3 minIdx,
vtkm::Id3 maxIdx) const;
void GetBoundaryVertices(IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundaryContourTreeMeshExec* meshBoundaryExecObj //input
) const;
private:
vtkm::cont::Invoker Invoke;
@ -793,6 +800,31 @@ MeshBoundaryContourTreeMeshExec ContourTreeMesh<FieldType>::GetMeshBoundaryExecu
this->GlobalMeshIndex, totalNRows, totalNCols, minIdx, maxIdx);
}
template <typename FieldType>
void ContourTreeMesh<FieldType>::GetBoundaryVertices(
IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundaryContourTreeMeshExec* meshBoundaryExecObj //input
) const
{
// start by generating a temporary array of indices
auto indexArray = vtkm::cont::ArrayHandleIndex(this->GlobalMeshIndex.GetNumberOfValues());
// compute the boolean array indicating which values lie on the boundary
vtkm::cont::ArrayHandle<bool> isOnBoundary;
ComputeMeshBoundaryContourTreeMesh computeMeshBoundaryContourTreeMeshWorklet;
this->Invoke(computeMeshBoundaryContourTreeMeshWorklet,
indexArray, // input
*meshBoundaryExecObj, // input
isOnBoundary // outut
);
// we will conditionally copy the boundary vertices' indices, capturing the end iterator to compute the # of boundary vertices
vtkm::cont::Algorithm::CopyIf(indexArray, isOnBoundary, boundaryVertexArray);
// duplicate these into the index array, since the BRACT uses indices into the underlying mesh anyway
vtkm::cont::Algorithm::Copy(boundaryVertexArray, boundarySortIndexArray);
}
} // namespace contourtree_augmented
} // worklet
} // vtkm

@ -57,8 +57,9 @@
#include <vtkm/Types.h>
#include <vtkm/worklet/contourtree_augmented/Mesh_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshBoundary.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshStructureFreudenthal2D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/ComputeMeshBoundary2D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundary2D.h>
#include <vtkm/cont/ExecutionObjectBase.h>
@ -88,6 +89,12 @@ public:
MeshBoundary2DExec GetMeshBoundaryExecutionObject() const;
void GetBoundaryVertices(IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary2DExec* meshBoundaryExecObj =
NULL // optional input, included for consistency with ContourTreeMesh
) const;
private:
bool UseGetMax; // Define the behavior ofr the PrepareForExecution function
}; // class Mesh_DEM_Triangulation
@ -136,6 +143,29 @@ Mesh_DEM_Triangulation_2D_Freudenthal<T, StorageType>::GetMeshBoundaryExecutionO
return MeshBoundary2DExec(this->NumColumns, this->NumRows, this->SortOrder);
}
template <typename T, typename StorageType>
void Mesh_DEM_Triangulation_2D_Freudenthal<T, StorageType>::GetBoundaryVertices(
IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary2DExec*
meshBoundaryExecObj // optional input, included for consistency with ContourTreeMesh
) const
{
vtkm::Id numBoundary = 2 * this->NumRows + 2 * this->NumColumns - 4;
auto boundaryId = vtkm::cont::ArrayHandleIndex(numBoundary);
ComputeMeshBoundary2D computeMeshBoundary2dWorklet;
this->Invoke(computeMeshBoundary2dWorklet,
boundaryId, // input
this->SortIndices, // input
(meshBoundaryExecObj == NULL) ? this->GetMeshBoundaryExecutionObject()
: *meshBoundaryExecObj, // input
boundaryVertexArray, // output
boundarySortIndexArray // output
);
}
} // namespace contourtree_augmented
} // worklet
} // vtkm

@ -61,9 +61,10 @@
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/worklet/contourtree_augmented/Mesh_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshBoundary.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshStructureFreudenthal3D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/freudenthal_3D/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/ComputeMeshBoundary3D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundary3D.h>
namespace vtkm
{
@ -93,6 +94,12 @@ public:
MeshBoundary3DExec GetMeshBoundaryExecutionObject() const;
void GetBoundaryVertices(IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary3DExec* meshBoundaryExecObj =
NULL // optional input, included for consistency with ContourTreeMesh
) const;
private:
bool UseGetMax; // Define the behavior ofr the PrepareForExecution function
}; // class Mesh_DEM_Triangulation
@ -152,6 +159,28 @@ Mesh_DEM_Triangulation_3D_Freudenthal<T, StorageType>::GetMeshBoundaryExecutionO
return MeshBoundary3DExec(this->NumColumns, this->NumRows, this->NumSlices, this->SortOrder);
}
template <typename T, typename StorageType>
void Mesh_DEM_Triangulation_3D_Freudenthal<T, StorageType>::GetBoundaryVertices(
IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary3DExec* meshBoundaryExecObj // input
) const
{
vtkm::Id numBoundary = 2 * this->NumRows * this->NumColumns // xy faces
+ 2 * this->NumRows * (this->NumSlices - 2) // yz faces - excluding vertices on xy
+ 2 * (this->NumColumns - 2) * (this->NumSlices - 2); // xz face interiors
auto boundaryId = vtkm::cont::ArrayHandleIndex(numBoundary);
ComputeMeshBoundary3D computeMeshBoundary3dWorklet;
this->Invoke(computeMeshBoundary3dWorklet,
boundaryId, // input
this->SortIndices, // input
(meshBoundaryExecObj == NULL) ? this->GetMeshBoundaryExecutionObject()
: *meshBoundaryExecObj, // input
boundaryVertexArray, // output
boundarySortIndexArray // output
);
}
} // namespace contourtree_augmented
} // worklet
} // vtkm

@ -61,9 +61,10 @@
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/worklet/contourtree_augmented/Mesh_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshBoundary.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/MeshStructureMarchingCubes.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/marchingcubes_3D/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/ComputeMeshBoundary3D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/mesh_boundary/MeshBoundary3D.h>
namespace vtkm
{
@ -97,6 +98,12 @@ public:
MeshBoundary3DExec GetMeshBoundaryExecutionObject() const;
void GetBoundaryVertices(IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary3DExec* meshBoundaryExecObj =
NULL // optional input, included for consistency with ContourTreeMesh
) const;
private:
bool UseGetMax; // Define the behavior ofr the PrepareForExecution function
}; // class Mesh_DEM_Triangulation
@ -181,6 +188,28 @@ Mesh_DEM_Triangulation_3D_MarchingCubes<T, StorageType>::GetMeshBoundaryExecutio
return MeshBoundary3DExec(this->NumColumns, this->NumRows, this->NumSlices, this->SortOrder);
}
template <typename T, typename StorageType>
void Mesh_DEM_Triangulation_3D_MarchingCubes<T, StorageType>::GetBoundaryVertices(
IdArrayType& boundaryVertexArray, // output
IdArrayType& boundarySortIndexArray, // output
MeshBoundary3DExec* meshBoundaryExecObj // input
) const
{
vtkm::Id numBoundary = 2 * this->NumRows * this->NumColumns // xy faces
+ 2 * this->NumRows * (this->NumSlices - 2) // yz faces - excluding vertices on xy
+ 2 * (this->NumColumns - 2) * (this->NumSlices - 2); // xz face interiors
auto boundaryId = vtkm::cont::ArrayHandleIndex(numBoundary);
ComputeMeshBoundary3D computeMeshBoundary3dWorklet;
this->Invoke(computeMeshBoundary3dWorklet,
boundaryId, // input
this->SortIndices, // input
(meshBoundaryExecObj == NULL) ? this->GetMeshBoundaryExecutionObject()
: *meshBoundaryExecObj, // input
boundaryVertexArray, // output
boundarySortIndexArray // output
);
}
} // namespace contourtree_augmented
} // worklet
} // vtkm

@ -105,7 +105,6 @@ public:
nneighboursVal);
// Implements in reference code
// #pragma omp parallel for
// The following is save since each global index is only written by one entry
// for (indexVector::size_type vtx = 0; vtx < nNeighbours.size(); ++vtx)
// {

@ -102,7 +102,6 @@ public:
}
// In serial this worklet implements the following operation
// #pragma omp parallel for
// for (indexVector::size_type from = 0; from < arcs.size(); ++from)
// {
// indexType to = arcs[from];

@ -110,7 +110,6 @@ public:
}
// In serial this worklet implements the following operation
// #pragma omp parallel for
// for (indexVector::size_type startVtxNo = 0; startVtxNo < firstNeighbour.size()-1; ++startVtxNo)
// {
// nNeighbours[startVtxNo] = firstNeighbour[startVtxNo+1] - firstNeighbour[startVtxNo];

@ -114,7 +114,6 @@ public:
}
// In serial this worklet implements the following operation
// #pragma omp parallel for
// for (indexVector::size_type sortedArcNo = 1; sortedArcNo < neighbours.size(); ++sortedArcNo)
// {
// indexType prevFrom = (neighbours[sortedArcNo-1] % 2 == 0) ? neighbours[sortedArcNo-1]/2 : MaskedIndex(arcs[neighbours[sortedArcNo-1]/2]);

@ -125,8 +125,6 @@ public:
}
/* Reference code implemented by this worklet
#pragma omp parallel for
for (indexVector::size_type vtx = 0; vtx < combinedFirstNeighbour.size(); ++vtx)
{
if (combinedOtherStartIndex[vtx]) // Needs merge

@ -122,7 +122,6 @@ public:
This worklet implemnts the following two loops from the original OpenMP code
The two loops are the same but the arrays required are different
#pragma omp parallel for
for (indexVector::size_type vtx = 0; vtx < firstNeighbour.size(); ++vtx)
{
indexType numNeighbours = (vtx < GetNumberOfVertices() - 1) ? firstNeighbour[vtx+1] - firstNeighbour[vtx] : neighbours.size() - firstNeighbour[vtx];
@ -133,7 +132,6 @@ public:
}
}
#pragma omp parallel for
for (indexVector::size_type vtx = 0; vtx < other.firstNeighbour.size(); ++vtx)
{
indexType numNeighbours = (vtx < other.GetNumberOfVertices() - 1) ? other.firstNeighbour[vtx+1] - other.firstNeighbour[vtx] : other.neighbours.size() - other.firstNeighbour[vtx];

@ -0,0 +1,20 @@
##============================================================================
## 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
MeshBoundary2D.h
MeshBoundary3D.h
MeshBoundaryContourTreeMesh.h
ComputeMeshBoundary2D.h
ComputeMeshBoundary3D.h
ComputeMeshBoundaryContourTreeMesh.h
)
#-----------------------------------------------------------------------------
vtkm_declare_headers(${headers})

@ -0,0 +1,155 @@
//============================================================================
// 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_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_2D_h
#define vtk_m_worklet_contourtree_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_2D_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
// Worklet to collapse past regular vertices by updating inbound and outbound as part
// loop to find the now-regular vertices and collapse past them without altering
// the existing join & split arcs
class ComputeMeshBoundary2D : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn boundaryId, // (input)
WholeArrayIn sortIndices, // (input)
ExecObject meshBoundary, // (input)
FieldOut boundaryVertexArray, // output
FieldOut boundarySortIndexArray // output
);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeMeshBoundary2D() {}
template <typename InFieldPortalType, typename MeshBoundaryType>
VTKM_EXEC void operator()(const vtkm::Id& boundaryId,
const InFieldPortalType sortIndicesPortal,
const MeshBoundaryType& meshBoundary,
vtkm::Id& boundaryVertex,
vtkm::Id& boundarySortIndex)
{
auto meshStructure2D = meshBoundary.GetMeshStructure();
vtkm::Id numBoundary = 2 * meshStructure2D.NumRows + 2 * meshStructure2D.NumColumns - 4;
// Define the boundaryVertex result
if (boundaryId < meshStructure2D->NumColumns)
{
boundaryVertex = meshStructure2D.VertexId(0, boundaryId);
}
// then bottom row
else if (boundaryId > numBoundary - meshStructure2D.NumColumns - 1)
{
boundaryVertex = meshStructure2D.VertexId(
meshStructure2D.NumRows - 1, boundaryId + meshStructure2D.NumColumns - numBoundary);
}
// then the row ends
else
{ // row ends
vtkm::Id row = ((boundaryId - meshStructure2D.NumColumns) / 2) + 1;
vtkm::Id col =
((boundaryId - meshStructure2D.NumColumns) % 2) ? (meshStructure2D.NumColumnsn - 1) : 0;
boundaryVertex = meshStructure2D.VertexId(row, col);
} // row ends
// and fill in the sort index array as well
boundarySortIndex = sortIndicesPortal.Get(boundaryVertex);
/*
// compute how many elements are needed
indexType nBoundary = 2 * nRows + 2 * nCols - 4;
boundaryVertexArray.resize(nBoundary);
boundarySortIndexArray.resize(nBoundary);
// loop to add in the vertices
// NB: the arithmetic here is chosen to guarantee that the vertex indices
// are in sorted order in the output - I'm not sure that this is necessary, but . . .
for (indexType boundaryId = 0; boundaryId < nBoundary; boundaryId++)
{ // loop through indices
// do top row first
if (boundaryId < nCols)
boundaryVertexArray[boundaryId] = vertexId(0, boundaryId);
// then bottom row
else if (boundaryId > nBoundary - nCols - 1)
boundaryVertexArray[boundaryId] = vertexId(nRows - 1, boundaryId + nCols - nBoundary);
// then the row ends
else
{ // row ends
indexType row = ((boundaryId - nCols) / 2) + 1;
indexType col = ((boundaryId - nCols) % 2) ? (nCols - 1) : 0;
boundaryVertexArray[boundaryId] = vertexId(row, col);
} // row ends
// and fill in the index array as well
boundarySortIndexArray[boundaryId] = sortIndices[boundaryVertexArray[boundaryId]];
} // loop through indices
*/
}
}; // ComputeMeshBoundary2D
} // namespace contourtree_augmented
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,223 @@
//============================================================================
// 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_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_3D_h
#define vtk_m_worklet_contourtree_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_3D_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
// Worklet to collapse past regular vertices by updating inbound and outbound as part
// loop to find the now-regular vertices and collapse past them without altering
// the existing join & split arcs
class ComputeMeshBoundary3D : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn boundaryId, // (input)
WholeArrayIn sortIndices, // (input)
ExecObject meshBoundary, // (input)
FieldOut boundaryVertexArray, // output
FieldOut boundarySortIndexArray // output
);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeMeshBoundary3D() {}
template <typename InFieldPortalType, typename MeshBoundaryType>
VTKM_EXEC void operator()(const vtkm::Id& boundaryId,
const InFieldPortalType sortIndicesPortal,
const MeshBoundaryType& meshBoundary,
vtkm::Id& boundaryVertex,
vtkm::Id& boundarySortIndex)
{
auto meshStructure3D = meshBoundary.GetMeshStructure();
vtkm::Id nRows = meshStructure3D.NumRows;
vtkm::Id nCols = meshStructure3D.NumCols;
vtkm::Id nSlices = meshStructure3D.NumSlices;
// calculate the number of boundary elements - all of the two xy faces
vtkm::Id nBoundary = 2 * nRows * nCols // xy faces
+ 2 * nRows * (nSlices - 2) // yz faces - excluding vertices on xy
+ 2 * (nCols - 2) * (nSlices - 2); // xz face interiors
vtkm::Id row = 0, col = 0, slice = 0;
vtkm::Id sliceSize = nRows * nCols;
vtkm::Id sliceBoundarySize = 2 * nRows + 2 * nCols - 4;
// do top plane first
if (boundaryId < sliceSize)
{ // top plane
row = boundaryId / nCols;
col = boundaryId % nCols;
slice = 0;
} // top plane
// then bottom plane
else if (boundaryId >= nBoundary - sliceSize)
{ // bottom plane
row = (boundaryId - (nBoundary - sliceSize)) / nCols;
col = (boundaryId - (nBoundary - sliceSize)) % nCols;
slice = nSlices - 1;
} // bottom plane
// now we have to deal with the exterior of the remaining slices
else
{ // slice exteriors
// first we subtract the size of the first slice
vtkm::Id offsetBoundaryid = boundaryId - sliceSize;
// now we can compute the slice id
slice = 1 + offsetBoundaryid / sliceBoundarySize;
// compute the local id on the slice
vtkm::Id sliceBoundaryid = offsetBoundaryid % sliceBoundarySize;
// now test for the first and last row
if (sliceBoundaryid < nCols)
{ // first row
row = 0;
col = sliceBoundaryid;
} // first row
else if (sliceBoundaryid >= (sliceBoundarySize - nCols))
{ // last row
row = nRows - 1;
col = sliceBoundaryid - (sliceBoundarySize - nCols);
} // last row
else
{ // any other row
row = ((sliceBoundaryid - nCols) / 2) + 1;
col = ((sliceBoundaryid - nCols) % 2) ? (nCols - 1) : 0;
} // any other row
} // slice exteriors
// now we have row, col, slice all set, compute the actual ID
boundaryVertex = meshStructure3D.VertexId(slice, row, col);
// and fill in the index array as well
boundarySortIndex = sortIndicesPortal.Get(boundaryVertex);
/*
{ // GetBoundaryVertices()
// calculate the number of boundary elements - all of the two xy faces
indexType nBoundary = 2 * nRows * nCols // xy faces
+ 2 * nRows * (nSlices - 2) // yz faces - excluding vertices on xy
+ 2 * (nCols - 2) * (nSlices - 2) // xz face interiors
;
// resize the arrays accordingly
boundaryVertexArray.resize(nBoundary);
boundarySortIndexArray.resize(nBoundary);
// loop to add in the vertices
for (indexType boundaryID = 0; boundaryID < nBoundary; boundaryID++)
{ // loop through indices
indexType row = 0, col = 0, slice = 0;
indexType sliceSize = nRows * nCols;
indexType sliceBoundarySize = 2 * nRows + 2 * nCols - 4;
// do top plane first
if (boundaryID < sliceSize)
{ // top plane
row = boundaryID / nCols;
col = boundaryID % nCols;
slice = 0;
} // top plane
// then bottom plane
else if (boundaryID >= nBoundary - sliceSize)
{ // bottom plane
row = (boundaryID - (nBoundary - sliceSize)) / nCols;
col = (boundaryID - (nBoundary - sliceSize)) % nCols;
slice = nSlices - 1;
} // bottom plane
// now we have to deal with the exterior of the remaining slices
else
{ // slice exteriors
// first we subtract the size of the first slice
indexType offsetBoundaryID = boundaryID - sliceSize;
// now we can compute the slice ID
slice = 1 + offsetBoundaryID / sliceBoundarySize;
// compute the local ID on the slice
indexType sliceBoundaryID = offsetBoundaryID % sliceBoundarySize;
// now test for the first and last row
if (sliceBoundaryID < nCols)
{ // first row
row = 0;
col = sliceBoundaryID;
} // first row
else if (sliceBoundaryID >= (sliceBoundarySize - nCols))
{ // last row
row = nRows - 1;
col = sliceBoundaryID - (sliceBoundarySize - nCols);
} // last row
else
{ // any other row
row = ((sliceBoundaryID - nCols) / 2) + 1;
col = ((sliceBoundaryID - nCols) % 2) ? (nCols - 1) : 0;
} // any other row
} // slice exteriors
// now we have row, col, slice all set, compute the actual ID
boundaryVertexArray[boundaryID] = vertexId(slice, row, col);
// and fill in the index array as well
boundarySortIndexArray[boundaryID] = sortIndices[boundaryVertexArray[boundaryID]];
} // loop through indices
} // GetBoundaryVertices()
*/
}
}; // ComputeMeshBoundary3D
} // namespace contourtree_augmented
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,103 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_worklet_contourtree_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_contour_tree_mesh_h
#define vtk_m_worklet_contourtree_augmented_mesh_dem_mesh_types_mesh_boundary_compute_mesh_boundary_contour_tree_mesh_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
// Worklet to collapse past regular vertices by updating inbound and outbound as part
// loop to find the now-regular vertices and collapse past them without altering
// the existing join & split arcs
class ComputeMeshBoundaryContourTreeMesh : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn nodeIndex, // (input)
ExecObject meshBoundary, // (input)
FieldOut isOnBoundary // (output)
);
typedef void ExecutionSignature(_1, _2, _3);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeMeshBoundaryContourTreeMesh() {}
template <typename InFieldPortalType, typename MeshBoundaryType>
VTKM_EXEC void operator()(const vtkm::Id& nodeIndex,
const MeshBoundaryType& meshBoundary,
vtkm::Id& isOnBoundary)
{
isOnBoundary = meshBoundary.liesOnBoundary(nodeIndex);
/*
indexVector isOnBoundary(globalMeshIndex.size());
for (indexType node = 0; node < globalMeshIndex.size(); node++)
isOnBoundary[node] = liesOnBoundary(node);
*/
}
}; // ComputeMeshBoundaryContourTreeMesh
} // namespace contourtree_augmented
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,153 @@
//============================================================================
// 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)
//==============================================================================
// This header contains a collection of classes used to describe the boundary
// of a mesh, for each main mesh type (i.e., 2D, 3D, and ContourTreeMesh).
// For each mesh type, there are two classes, the actual boundary desriptor
// class and an ExectionObject class with the PrepareForInput function that
// VTKm expects to generate the object for the execution environment.
#ifndef vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_2d_h
#define vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_2d_h
#include <cstdlib>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/MeshStructure2D.h>
#include <vtkm/cont/ExecutionObjectBase.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
template <typename DeviceTag>
class MeshBoundary2D
{
public:
// Sort indicies types
using SortOrderPortalType = typename IdArrayType::template ExecutionTypes<DeviceTag>::PortalConst;
VTKM_EXEC_CONT
MeshBoundary2D()
: MeshStructure(mesh_dem::MeshStructure2D<DeviceTag>(0, 0))
{
}
VTKM_CONT
MeshBoundary2D(vtkm::Id nrows,
vtkm::Id ncols,
const IdArrayType& sortOrder,
vtkm::cont::Token& token)
: MeshStructure(mesh_dem::MeshStructure2D<DeviceTag>(nrows, ncols))
{
this->SortOrderPortal = sortOrder.PrepareForInput(DeviceTag(), token);
}
VTKM_EXEC_CONT
bool liesOnBoundary(const vtkm::Id index) const
{
vtkm::Id meshSortOrderValue = this->SortOrderPortal.Get(index);
const vtkm::Id row = this->MeshStructure.VertexRow(meshSortOrderValue);
const vtkm::Id col = this->MeshStructure.VertexColumn(meshSortOrderValue);
return (row == 0) || (col == 0) || (row == this->MeshStructure.NumRows - 1) ||
(col == this->MeshStructure.NumColumns - 1);
}
VTKM_EXEC_CONT
const mesh_dem::MeshStructure2D<DeviceTag>& GetMeshStructure() const
{
return this->MeshStructure;
}
private:
// 2D Mesh size parameters
mesh_dem::MeshStructure2D<DeviceTag> MeshStructure;
SortOrderPortalType SortOrderPortal;
};
class MeshBoundary2DExec : public vtkm::cont::ExecutionObjectBase
{
public:
VTKM_EXEC_CONT
MeshBoundary2DExec(vtkm::Id nrows, vtkm::Id ncols, const IdArrayType& inSortOrder)
: NumRows(nrows)
, NumColumns(ncols)
, SortOrder(inSortOrder)
{
}
VTKM_CONT
template <typename DeviceTag>
MeshBoundary2D<DeviceTag> PrepareForExecution(DeviceTag, vtkm::cont::Token& token) const
{
return MeshBoundary2D<DeviceTag>(this->NumRows, this->NumColumns, this->SortOrder, token);
}
private:
// 2D Mesh size parameters
vtkm::Id NumRows;
vtkm::Id NumColumns;
const IdArrayType& SortOrder;
};
} // namespace contourtree_augmented
} // worklet
} // vtkm
#endif

@ -0,0 +1,154 @@
//============================================================================
// 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)
//==============================================================================
// This header contains a collection of classes used to describe the boundary
// of a mesh, for each main mesh type (i.e., 2D, 3D, and ContourTreeMesh).
// For each mesh type, there are two classes, the actual boundary desriptor
// class and an ExectionObject class with the PrepareForInput function that
// VTKm expects to generate the object for the execution environment.
#ifndef vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_3d_h
#define vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_3d_h
#include <cstdlib>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/MeshStructure3D.h>
#include <vtkm/cont/ExecutionObjectBase.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_augmented
{
template <typename DeviceTag>
class MeshBoundary3D : public vtkm::cont::ExecutionObjectBase
{
public:
// Sort indicies types
using SortOrderPortalType = typename IdArrayType::template ExecutionTypes<DeviceTag>::PortalConst;
VTKM_EXEC_CONT
MeshBoundary3D()
: MeshStructure(mesh_dem::MeshStructure3D<DeviceTag>(0, 0, 0))
{
}
VTKM_CONT
MeshBoundary3D(vtkm::Id nrows,
vtkm::Id ncols,
vtkm::Id nslices,
const IdArrayType& sortOrder,
vtkm::cont::Token& token)
: MeshStructure(mesh_dem::MeshStructure3D<DeviceTag>(nrows, ncols, nslices))
{
this->SortOrderPortal = sortOrder.PrepareForInput(DeviceTag(), token);
}
VTKM_EXEC_CONT
bool liesOnBoundary(const vtkm::Id index) const
{
vtkm::Id meshSortOrderValue = this->SortOrderPortal.Get(index);
const vtkm::Id row = this->MeshStructure.VertexRow(meshSortOrderValue);
const vtkm::Id col = this->MeshStructure.VertexColumn(meshSortOrderValue);
const vtkm::Id sli = this->MeshStructure.VertexSlice(meshSortOrderValue);
return (row == 0) || (col == 0) || (sli == 0) || (row == this->MeshStructure.NumRows - 1) ||
(col == this->MeshStructure.NumColumns - 1) || (sli == this->MeshStructure.NumSlices - 1);
}
protected:
// 3D Mesh size parameters
mesh_dem::MeshStructure3D<DeviceTag> MeshStructure;
SortOrderPortalType SortOrderPortal;
};
class MeshBoundary3DExec : public vtkm::cont::ExecutionObjectBase
{
public:
VTKM_EXEC_CONT
MeshBoundary3DExec(vtkm::Id nrows,
vtkm::Id ncols,
vtkm::Id nslices,
const IdArrayType& inSortOrder)
: NumRows(nrows)
, NumColumns(ncols)
, NumSlices(nslices)
, SortOrder(inSortOrder)
{
}
VTKM_CONT
template <typename DeviceTag>
MeshBoundary3D<DeviceTag> PrepareForExecution(DeviceTag, vtkm::cont::Token& token) const
{
return MeshBoundary3D<DeviceTag>(
this->NumRows, this->NumColumns, this->NumSlices, this->SortOrder, token);
}
protected:
// 3D Mesh size parameters
vtkm::Id NumRows;
vtkm::Id NumColumns;
vtkm::Id NumSlices;
const IdArrayType& SortOrder;
};
} // namespace contourtree_augmented
} // worklet
} // vtkm
#endif

@ -56,16 +56,13 @@
// class and an ExectionObject class with the PrepareForInput function that
// VTKm expects to generate the object for the execution environment.
#ifndef vtk_m_worklet_contourtree_augmented_mesh_boundary_h
#define vtk_m_worklet_contourtree_augmented_mesh_boundary_h
#ifndef vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_contour_tree_mesh_h
#define vtk_m_worklet_contourtree_augmented_mesh_boundary_mesh_boundary_contour_tree_mesh_h
#include <cstdlib>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/MeshStructure2D.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/MeshStructure3D.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
@ -75,145 +72,6 @@ namespace contourtree_augmented
{
template <typename DeviceTag>
class MeshBoundary2D
{
public:
// Sort indicies types
using SortOrderPortalType = typename IdArrayType::template ExecutionTypes<DeviceTag>::PortalConst;
VTKM_EXEC_CONT
MeshBoundary2D()
: MeshStructure(mesh_dem::MeshStructure2D<DeviceTag>(0, 0))
{
}
VTKM_CONT
MeshBoundary2D(vtkm::Id nrows,
vtkm::Id ncols,
const IdArrayType& sortOrder,
vtkm::cont::Token& token)
: MeshStructure(mesh_dem::MeshStructure2D<DeviceTag>(nrows, ncols))
{
this->SortOrderPortal = sortOrder.PrepareForInput(DeviceTag(), token);
}
VTKM_EXEC_CONT
bool liesOnBoundary(const vtkm::Id index) const
{
vtkm::Id meshSortOrderValue = this->SortOrderPortal.Get(index);
const vtkm::Id row = this->MeshStructure.VertexRow(meshSortOrderValue);
const vtkm::Id col = this->MeshStructure.VertexColumn(meshSortOrderValue);
return (row == 0) || (col == 0) || (row == this->MeshStructure.NumRows - 1) ||
(col == this->MeshStructure.NumColumns - 1);
}
private:
// 2D Mesh size parameters
mesh_dem::MeshStructure2D<DeviceTag> MeshStructure;
SortOrderPortalType SortOrderPortal;
};
class MeshBoundary2DExec : public vtkm::cont::ExecutionObjectBase
{
public:
VTKM_EXEC_CONT
MeshBoundary2DExec(vtkm::Id nrows, vtkm::Id ncols, const IdArrayType& inSortOrder)
: NumRows(nrows)
, NumColumns(ncols)
, SortOrder(inSortOrder)
{
}
VTKM_CONT
template <typename DeviceTag>
MeshBoundary2D<DeviceTag> PrepareForExecution(DeviceTag, vtkm::cont::Token& token) const
{
return MeshBoundary2D<DeviceTag>(this->NumRows, this->NumColumns, this->SortOrder, token);
}
private:
// 2D Mesh size parameters
vtkm::Id NumRows;
vtkm::Id NumColumns;
const IdArrayType& SortOrder;
};
template <typename DeviceTag>
class MeshBoundary3D : public vtkm::cont::ExecutionObjectBase
{
public:
// Sort indicies types
using SortOrderPortalType = typename IdArrayType::template ExecutionTypes<DeviceTag>::PortalConst;
VTKM_EXEC_CONT
MeshBoundary3D()
: MeshStructure(mesh_dem::MeshStructure3D<DeviceTag>(0, 0, 0))
{
}
VTKM_CONT
MeshBoundary3D(vtkm::Id nrows,
vtkm::Id ncols,
vtkm::Id nslices,
const IdArrayType& sortOrder,
vtkm::cont::Token& token)
: MeshStructure(mesh_dem::MeshStructure3D<DeviceTag>(nrows, ncols, nslices))
{
this->SortOrderPortal = sortOrder.PrepareForInput(DeviceTag(), token);
}
VTKM_EXEC_CONT
bool liesOnBoundary(const vtkm::Id index) const
{
vtkm::Id meshSortOrderValue = this->SortOrderPortal.Get(index);
const vtkm::Id row = this->MeshStructure.VertexRow(meshSortOrderValue);
const vtkm::Id col = this->MeshStructure.VertexColumn(meshSortOrderValue);
const vtkm::Id sli = this->MeshStructure.VertexSlice(meshSortOrderValue);
return (row == 0) || (col == 0) || (sli == 0) || (row == this->MeshStructure.NumRows - 1) ||
(col == this->MeshStructure.NumColumns - 1) || (sli == this->MeshStructure.NumSlices - 1);
}
protected:
// 3D Mesh size parameters
mesh_dem::MeshStructure3D<DeviceTag> MeshStructure;
SortOrderPortalType SortOrderPortal;
};
class MeshBoundary3DExec : public vtkm::cont::ExecutionObjectBase
{
public:
VTKM_EXEC_CONT
MeshBoundary3DExec(vtkm::Id nrows,
vtkm::Id ncols,
vtkm::Id nslices,
const IdArrayType& inSortOrder)
: NumRows(nrows)
, NumColumns(ncols)
, NumSlices(nslices)
, SortOrder(inSortOrder)
{
}
VTKM_CONT
template <typename DeviceTag>
MeshBoundary3D<DeviceTag> PrepareForExecution(DeviceTag, vtkm::cont::Token& token) const
{
return MeshBoundary3D<DeviceTag>(
this->NumRows, this->NumColumns, this->NumSlices, this->SortOrder, token);
}
protected:
// 3D Mesh size parameters
vtkm::Id NumRows;
vtkm::Id NumColumns;
vtkm::Id NumSlices;
const IdArrayType& SortOrder;
};
template <typename DeviceTag>
class MeshBoundaryContourTreeMesh

@ -0,0 +1,288 @@
//============================================================================
// 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_boundary_restricted_augmented_contour_tree_h
#define vtk_m_worklet_contourtree_distributed_boundary_restricted_augmented_contour_tree_h
#include <vtkm/Types.h>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/IdRelabeler.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/ContourTreeMesh.h>
#include <sstream>
#include <string>
#include <utility>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
/// \brief Boundary Restricted Augmented Contour Tree (BRACT)
///
/// 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
/// (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 BRACT
public:
// for each vertex, we store the index
vtkm::worklet::contourtree_augmented::IdArrayType VertexIndex;
// and the ID of the vertex it connects to (or NO_SUCH_ELEMENT)
vtkm::worklet::contourtree_augmented::IdArrayType Superarcs;
// prints the contents of the BRACT for comparison with sweep and merge
std::string Print();
// secondary version which takes the mesh as a parameter
template <typename Mesh, typename FieldArrayType>
std::string PrintGlobalDot(const char* label,
const Mesh& mesh,
const FieldArrayType& fieldArray,
const vtkm::Id3 blockOrigin,
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);
// prints the contents of the BRACT in debug format
std::string DebugPrint(const char* message, const char* fileName, long lineNum);
};
// prints the contents of the BRACT for comparison with sweep and merge
std::string BoundaryRestrictedAugmentedContourTree::Print()
{ // Print
// Use string steam to record text so the user can print it however they like
std::stringstream resultStream;
resultStream << "Boundary-Restricted Augmented Contour Tree" << std::endl;
resultStream << "==========================================" << std::endl;
// fill it up
auto superarcsPortal = this->Superarcs.ReadPortal();
auto vertexIndexPortal = this->VertexIndex.ReadPortal();
for (vtkm::Id node = 0; node < superarcsPortal.GetNumberOfValues(); node++)
{
// retrieve ID of target supernode
vtkm::Id from = vertexIndexPortal.Get(node);
vtkm::Id to = superarcsPortal.Get(node);
// if this is true, it is the last pruned vertex & is omitted
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
{
continue;
}
// print out the from & to
resultStream << std::setw(vtkm::worklet::contourtree_augmented::PRINT_WIDTH) << from << " ";
resultStream << std::setw(vtkm::worklet::contourtree_augmented::PRINT_WIDTH) << to << std::endl;
}
return resultStream.str();
} // 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
{ // PrintGlobalDot
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]);
// loop through all nodes
auto vertexIndexPortal = this->VertexIndex.ReadPortal();
auto superarcsPortal = this->Superarcs.ReadPortal();
auto sortOrderPortal = mesh.SortOrder.ReadPortal();
auto fieldArrayPortal = fieldArray.ReadPortal();
for (vtkm::Id node = 0; node < this->Superarcs.GetNumberOfValues(); node++)
{
// now convert to mesh IDs from node IDs
vtkm::Id from = vertexIndexPortal.Get(node);
// find the local & global IDs & data value
vtkm::Id fromLocal = sortOrderPortal.Get(from);
vtkm::Id fromGlobal = relabeler(fromLocal);
auto fromValue = fieldArrayPortal.Get(fromLocal);
// print the vertex
resultStream << node << " [style=filled,fillcolor="
<< "grey"
<< ",label=\"" << fromGlobal << "\\nv" << fromValue << "\"];" << std::endl;
}
for (vtkm::Id node = 0; node < this->Superarcs.GetNumberOfValues(); node++)
{
// retrieve ID of target supernode
vtkm::Id to = superarcsPortal.Get(node);
// if this is true, it is the last pruned vertex & is omitted
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
{
continue;
}
if (node < to)
{
resultStream << to << " -> " << node << std::endl;
}
else
{
resultStream << node << " -> " << to << std::endl;
}
}
resultStream << "\t}" << std::endl;
// return the result
return resultStream.str();
} // PrintGlobalDot
// prints the contents of the BRACT as a dot file using global IDs (version for CT mesh)
template <typename FieldType>
std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(
const char* label,
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh)
{ //PrintGlobalDot
std::stringstream resultStream;
// print the header information
resultStream << "digraph BRACT\n\t{\n";
resultStream << "\tsize=\"6.5, 9\"\n\tratio=\"fill\"\n";
resultStream << "\tlabel=\"" << label << "\"\n\tlabelloc=t\n\tfontsize=30\n" << std::endl;
// loop through all nodes
auto vertexIndexPortal = this->VertexIndex.ReadPortal();
auto globalMeshIndexPortal = mesh.GlobalMeshIndex.ReadPortal();
auto sortedValuesPortal = mesh.SortedValued.ReadPortal();
auto superarcsPortal = this->Superarcs.ReadPortal();
for (vtkm::Id node = 0; node < this->VertexIndex.GetNumberOfValues(); node++)
{ // per node
// work out the node and it's value
vtkm::Id meshIndex = vertexIndexPortal.Get(node);
vtkm::Id from = globalMeshIndexPortal.Get(meshIndex);
auto fromValue = sortedValuesPortal.Get(meshIndex);
// print the vertex
resultStream << node << " [style=filled,fillcolor="
<< "grey"
<< ",label=\"" << from << "\\nv" << fromValue << "\"];" << std::endl;
} // per node
for (vtkm::Id node = 0; node < this->Superarcs.GetNumberOfValues(); node++)
{ // per node
// retrieve ID of target supernode
vtkm::Id to = superarcsPortal.Get(node);
// if this is true, it is the last pruned vertex & is omitted
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
{
continue;
}
if (node < to)
{
resultStream << to << " -> " << node << std::endl;
}
else
{
resultStream << node << " -> " << to << std::endl;
}
} // per node
resultStream << "\t}" << std::endl;
// Return the resulting strin
return resultStream.str();
} //PrintGlobalDot
// debug routine
inline std::string BoundaryRestrictedAugmentedContourTree::DebugPrint(const char* message,
const char* fileName,
long lineNum)
{ // DebugPrint
std::stringstream resultStream;
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 << "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);
resultStream << "---------------------------" << std::endl;
resultStream << std::endl;
resultStream << std::flush;
return resultStream.str();
} // DebugPrint
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,23 @@
##============================================================================
## 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
ContourTreeBlockData.h
SpatialDecomposition.h
MultiBlockContourTreeHelper.h
MergeBlockFunctor.h
BoundaryRestrictedAugmentedContourTree.h
BoundaryRestrictedAugmentedContourTreeMaker.h
HierarchicalContourTree.h
)
vtkm_declare_headers(${headers})
add_subdirectory(bract_maker)

@ -0,0 +1,143 @@
//============================================================================
// 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>
// 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 ContourTreeBlockData
{
static void* create() { return new ContourTreeBlockData<FieldType>; }
static void destroy(void* b) { delete static_cast<ContourTreeBlockData<FieldType>*>(b); }
// 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::cont::ArrayHandle<FieldType> SortedValue;
vtkm::worklet::contourtree_augmented::IdArrayType GlobalMeshIndex;
vtkm::worklet::contourtree_augmented::IdArrayType Neighbours;
vtkm::worklet::contourtree_augmented::IdArrayType FirstNeighbour;
vtkm::Id MaxNeighbours;
// Block metadata
vtkm::Id3 BlockOrigin; // Origin of the data block
vtkm::Id3 BlockSize; // Extends of the data block
vtkm::Id3 GlobalSize; // Extends of the global mesh
unsigned int ComputeRegularStructure; // pass through augmentation setting
};
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
namespace vtkmdiy
{
// Struct to serialize ContourBlockData objects (i.e., load/save) needed in parralle for DIY
template <typename FieldType>
struct Serialization<vtkm::worklet::contourtree_distributed::ContourTreeBlockData<FieldType>>
{
static void save(
vtkmdiy::BinaryBuffer& bb,
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);
vtkmdiy::save(bb, block.FirstNeighbour);
vtkmdiy::save(bb, block.MaxNeighbours);
vtkmdiy::save(bb, block.BlockOrigin);
vtkmdiy::save(bb, block.BlockSize);
vtkmdiy::save(bb, block.GlobalSize);
vtkmdiy::save(bb, block.ComputeRegularStructure);
}
static void load(vtkmdiy::BinaryBuffer& bb,
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);
vtkmdiy::load(bb, block.FirstNeighbour);
vtkmdiy::load(bb, block.MaxNeighbours);
vtkmdiy::load(bb, block.BlockOrigin);
vtkmdiy::load(bb, block.BlockSize);
vtkmdiy::load(bb, block.GlobalSize);
vtkmdiy::load(bb, block.ComputeRegularStructure);
}
};
} // namespace mangled_vtkmdiy_namespace
#endif

@ -0,0 +1,83 @@
//============================================================================
// 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_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_contour_tree_h
#include <vtkm/Types.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
/// \brief Hierarchical Contour Tree data structure
///
/// TODO this class still needs to be implemented
class HierarchicalContourTree
{
public:
VTKM_CONT
HierarchicalContourTree() {}
};
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,250 @@
//============================================================================
// 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_mergeblockfunctor_h
#define vtk_m_worklet_contourtree_distributed_mergeblockfunctor_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 MergeFunctor
{
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>
void MergeBlockFunctor(
vtkm::worklet::contourtree_distributed::ContourTreeBlockData<FieldType>* block, // local Block.
const vtkmdiy::ReduceProxy& rp, // communication proxy
const vtkmdiy::RegularMergePartners& partners // partners of the current block
)
{ //MergeBlockFunctor
(void)partners; // Avoid unused parameter warning
const auto selfid = rp.gid();
// TODO This should be changed so that we have the ContourTree itself as the block and then the
// ContourTreeMesh would still be used for exchange. In this case we would need to compute
// the ContourTreeMesh at the beginning of the function for the current block every time
// but then we would not need to compute those meshes when we initialize vtkmdiy
// and we don't need to have the special case for rank 0.
// 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);
for (const int ingid : incoming)
{
if (ingid != selfid)
{
vtkm::worklet::contourtree_distributed::ContourTreeBlockData<FieldType> recvblock;
rp.dequeue(ingid, recvblock);
// Construct the two contour tree mesh by assignign the block data
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType> contourTreeMeshIn;
contourTreeMeshIn.NumVertices = recvblock.NumVertices;
contourTreeMeshIn.SortOrder = recvblock.SortOrder;
contourTreeMeshIn.SortedValues = recvblock.SortedValue;
contourTreeMeshIn.GlobalMeshIndex = recvblock.GlobalMeshIndex;
contourTreeMeshIn.Neighbours = recvblock.Neighbours;
contourTreeMeshIn.FirstNeighbour = recvblock.FirstNeighbour;
contourTreeMeshIn.MaxNeighbours = recvblock.MaxNeighbours;
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType> contourTreeMeshOut;
contourTreeMeshOut.NumVertices = block->NumVertices;
contourTreeMeshOut.SortOrder = block->SortOrder;
contourTreeMeshOut.SortedValues = block->SortedValue;
contourTreeMeshOut.GlobalMeshIndex = block->GlobalMeshIndex;
contourTreeMeshOut.Neighbours = block->Neighbours;
contourTreeMeshOut.FirstNeighbour = block->FirstNeighbour;
contourTreeMeshOut.MaxNeighbours = block->MaxNeighbours;
// Merge the two contour tree meshes
vtkm::cont::TryExecute(MergeFunctor{}, contourTreeMeshIn, contourTreeMeshOut);
// Compute the origin and size of the new block
vtkm::Id3 globalSize = block->GlobalSize;
vtkm::Id3 currBlockOrigin;
currBlockOrigin[0] = std::min(recvblock.BlockOrigin[0], block->BlockOrigin[0]);
currBlockOrigin[1] = std::min(recvblock.BlockOrigin[1], block->BlockOrigin[1]);
currBlockOrigin[2] = std::min(recvblock.BlockOrigin[2], block->BlockOrigin[2]);
vtkm::Id3 currBlockMaxIndex; // Needed only to compute the block size
currBlockMaxIndex[0] = std::max(recvblock.BlockOrigin[0] + recvblock.BlockSize[0],
block->BlockOrigin[0] + block->BlockSize[0]);
currBlockMaxIndex[1] = std::max(recvblock.BlockOrigin[1] + recvblock.BlockSize[1],
block->BlockOrigin[1] + block->BlockSize[1]);
currBlockMaxIndex[2] = std::max(recvblock.BlockOrigin[2] + recvblock.BlockSize[2],
block->BlockOrigin[2] + block->BlockSize[2]);
vtkm::Id3 currBlockSize;
currBlockSize[0] = currBlockMaxIndex[0] - currBlockOrigin[0];
currBlockSize[1] = currBlockMaxIndex[1] - currBlockOrigin[1];
currBlockSize[2] = currBlockMaxIndex[2] - currBlockOrigin[2];
// On rank 0 we compute the contour tree at the end when the merge is done, so we don't need to do it here
if (selfid == 0)
{
// Save the data from our block for the next iteration
block->NumVertices = contourTreeMeshOut.NumVertices;
block->SortOrder = contourTreeMeshOut.SortOrder;
block->SortedValue = contourTreeMeshOut.SortedValues;
block->GlobalMeshIndex = contourTreeMeshOut.GlobalMeshIndex;
block->Neighbours = contourTreeMeshOut.Neighbours;
block->FirstNeighbour = contourTreeMeshOut.FirstNeighbour;
block->MaxNeighbours = contourTreeMeshOut.MaxNeighbours;
block->BlockOrigin = currBlockOrigin;
block->BlockSize = currBlockSize;
block->GlobalSize = globalSize;
}
else // If we are a block that will continue to be merged then we need compute the contour tree here
{
// Compute the contour tree from our merged mesh
vtkm::Id currNumIterations;
vtkm::worklet::contourtree_augmented::ContourTree currContourTree;
vtkm::worklet::contourtree_augmented::IdArrayType currSortOrder;
vtkm::worklet::ContourTreeAugmented worklet;
vtkm::cont::ArrayHandle<FieldType> currField;
vtkm::Id3 maxIdx(currBlockOrigin[0] + currBlockSize[0] - 1,
currBlockOrigin[1] + currBlockSize[1] - 1,
currBlockOrigin[2] + currBlockSize[2] - 1);
auto meshBoundaryExecObj =
contourTreeMeshOut.GetMeshBoundaryExecutionObject(globalSize[0], // totalNRows
globalSize[1], // totalNCols
currBlockOrigin, // minIdx
maxIdx // maxIdx
);
worklet.Run(
contourTreeMeshOut.SortedValues, // Unused param. Provide something to keep the API happy
contourTreeMeshOut,
currContourTree,
currSortOrder,
currNumIterations,
block->ComputeRegularStructure,
meshBoundaryExecObj);
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>* newContourTreeMesh = 0;
if (block->ComputeRegularStructure == 1)
{
// If we have the fully augmented contour tree
newContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>(
currContourTree.Arcs, contourTreeMeshOut);
}
else if (block->ComputeRegularStructure == 2)
{
// If we have the partially augmented (e.g., boundary augmented) contour tree
newContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>(
currContourTree.Augmentnodes, currContourTree.Augmentarcs, contourTreeMeshOut);
}
else
{
// We should not be able to get here
throw vtkm::cont::ErrorFilterExecution(
"Parallel contour tree requires at least parial boundary augmentation");
}
// Copy the data from newContourTreeMesh into block
block->NumVertices = newContourTreeMesh->NumVertices;
block->SortOrder = newContourTreeMesh->SortOrder;
block->SortedValue = newContourTreeMesh->SortedValues;
block->GlobalMeshIndex = newContourTreeMesh->GlobalMeshIndex;
block->Neighbours = newContourTreeMesh->Neighbours;
block->FirstNeighbour = newContourTreeMesh->FirstNeighbour;
block->MaxNeighbours = newContourTreeMesh->MaxNeighbours;
block->BlockOrigin = currBlockOrigin;
block->BlockSize = currBlockSize;
block->GlobalSize = globalSize;
// VTKm keeps track of the arrays for us, so we can savely delete the ContourTreeMesh
// as all data has been transferred into our data block
delete newContourTreeMesh;
}
}
}
// 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);
}
}
} //end MergeBlockFunctor
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,218 @@
//============================================================================
// 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_multiblockcontourtreehelper_h
#define vtk_m_worklet_contourtree_distributed_multiblockcontourtreehelper_h
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem_meshtypes/ContourTreeMesh.h>
#include <vtkm/Types.h>
#include <vtkm/cont/BoundsCompute.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
//#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/worklet/contourtree_augmented/mesh_dem/IdRelabeler.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
//--- Helper class to help with the contstuction of the GlobalContourTree
class MultiBlockContourTreeHelper
{
public:
VTKM_CONT
MultiBlockContourTreeHelper(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)
: MultiBlockSpatialDecomposition(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes)
{
vtkm::Id localNumBlocks = this->GetLocalNumberOfBlocks();
LocalContourTrees.resize(static_cast<std::size_t>(localNumBlocks));
LocalSortOrders.resize(static_cast<std::size_t>(localNumBlocks));
}
VTKM_CONT
~MultiBlockContourTreeHelper(void)
{
LocalContourTrees.clear();
LocalSortOrders.clear();
}
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 vtkm::Id GetLocalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks();
}
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks();
}
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;
}
// Used to compute the local contour tree mesh in after DoExecute. I.e., the function is
// used in PostExecute to construct the initial set of local ContourTreeMesh blocks for
// DIY. Subsequent construction of updated ContourTreeMeshes is handled separately.
template <typename T>
inline static vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>*
ComputeLocalContourTreeMesh(const vtkm::Id3 localBlockOrigin,
const vtkm::Id3 localBlockSize,
const vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<T>& field,
const vtkm::worklet::contourtree_augmented::ContourTree& contourTree,
const vtkm::worklet::contourtree_augmented::IdArrayType& sortOrder,
unsigned int computeRegularStructure)
{
vtkm::Id startRow = localBlockOrigin[0];
vtkm::Id startCol = localBlockOrigin[1];
vtkm::Id startSlice = localBlockOrigin[2];
vtkm::Id numRows = localBlockSize[0];
vtkm::Id numCols = localBlockSize[1];
vtkm::Id totalNumRows = globalSize[0];
vtkm::Id totalNumCols = globalSize[1];
// compute the global mesh index and initalize the local contour tree mesh
if (computeRegularStructure == 1)
{
// Compute the global mesh index
vtkm::worklet::contourtree_augmented::IdArrayType localGlobalMeshIndex;
auto transformedIndex = vtkm::cont::ArrayHandleTransform<
vtkm::worklet::contourtree_augmented::IdArrayType,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler>(
sortOrder,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
startRow, startCol, startSlice, numRows, numCols, totalNumRows, totalNumCols));
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
// Compute the local contour tree mesh
auto localContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>(
contourTree.Arcs, sortOrder, field, localGlobalMeshIndex);
return localContourTreeMesh;
}
else if (computeRegularStructure == 2)
{
// 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(contourTree.Augmentnodes, sortOrder);
auto transformedIndex = vtkm::cont::make_ArrayHandleTransform(
permutedSortOrder,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
startRow, startCol, startSlice, numRows, numCols, totalNumRows, totalNumCols));
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
// Compute the local contour tree mesh
auto localContourTreeMesh = new vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>(
contourTree.Augmentnodes, contourTree.Augmentarcs, sortOrder, field, localGlobalMeshIndex);
return localContourTreeMesh;
}
else
{
// We should not be able to get here
throw vtkm::cont::ErrorFilterExecution(
"Parallel contour tree requires at least parial boundary augmentation");
}
}
SpatialDecomposition MultiBlockSpatialDecomposition;
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> LocalContourTrees;
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> LocalSortOrders;
}; // end MultiBlockContourTreeHelper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,139 @@
//============================================================================
// 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_spatialdecomposition_h
#define vtk_m_worklet_contourtree_distributed_spatialdecomposition_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
{
// --- Helper class to store the spatial decomposition defined by the PartitionedDataSet input data
class SpatialDecomposition
{
public:
VTKM_CONT
SpatialDecomposition(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)
: BlocksPerDimension(blocksPerDim)
, GlobalSize(globalSize)
, LocalBlockIndices(localBlockIndices)
, LocalBlockOrigins(localBlockOrigins)
, LocalBlockSizes(localBlockSizes)
{
}
inline vtkmdiy::DiscreteBounds GetVTKmDIYBounds() const
{
if (this->NumberOfDimensions() == 2)
{
// may need to change back when porting ot later verison of VTKM/vtkmdiy
vtkmdiy::DiscreteBounds domain(0); //(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]);
return domain;
}
else
{
// may need to change back when porting to later version of VTMK/vtkmdiy
vtkmdiy::DiscreteBounds domain(0); //(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]);
domain.max[2] = static_cast<int>(this->GlobalSize[2]);
return domain;
}
}
inline vtkm::Id NumberOfDimensions() const { return GlobalSize[2] > 1 ? 3 : 2; }
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return BlocksPerDimension[0] * BlocksPerDimension[1] * BlocksPerDimension[2];
}
inline vtkm::Id GetLocalNumberOfBlocks() const { return LocalBlockSizes.GetNumberOfValues(); }
// Number of blocks along each dimension
vtkm::Id3 BlocksPerDimension;
// Size of the global mesh
vtkm::Id3 GlobalSize;
// Index of the local blocks in x,y,z, i.e., in i,j,k mesh coordinates
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockIndices;
// Origin of the local blocks in mesh index space
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockOrigins;
// Size of each local block in x, y,z
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockSizes;
};
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,121 @@
//============================================================================
// 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_add_terminal_flags_to_up_down_neighbours_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_add_terminal_flags_to_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 bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class AddTerminalFlagsToUpDownNeighboursWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn newVertexId, // input
WholeArrayOut upNeighbour, // output
WholeArrayOut downNeighbour // output
);
using ExecutionSignature = void(InputIndex, _1, _2, _3);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
AddTerminalFlagsToUpDownNeighboursWorklet() {}
template <typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& returnIndex,
const vtkm::Id& newVertexIdValue,
const OutFieldPortalType& upNeighbourPortal,
const OutFieldPortalType& downNeighbourPortal)
{
// per vertex
// necessary vertices
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdValue))
{ // necessary vertex
// set both up & down neighbours to self with terminal element set
upNeighbourPortal.Set(returnIndex,
returnIndex | vtkm::worklet::contourtree_augmented::TERMINAL_ELEMENT);
downNeighbourPortal.Set(returnIndex,
returnIndex | vtkm::worklet::contourtree_augmented::TERMINAL_ELEMENT);
} // necessary vertex
// In serial this worklet implements the following operation
/*
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
{ // per vertex
// necessary vertices
if (!noSuchElement(newVertexID[returnIndex]))
{ // necessary vertex
// set both up & down neighbours to self with terminal element set
upNeighbour[returnIndex] = downNeighbour[returnIndex] = returnIndex | TERMINAL_ELEMENT;
} // necessary vertex
} // per vertex
*/
}
}; // AddTerminalFlagsToUpDownNeighboursWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,99 @@
//============================================================================
// 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_array_sum_functor_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_array_sum_functor_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
//Simple functor to implement a fancy array handle that returns the sum of two arrays
class ArraySumFunctor
{
public:
VTKM_EXEC_CONT
ArraySumFunctor() {}
VTKM_EXEC_CONT
ArraySumFunctor(const vtkm::worklet::contourtree_augmented::IdArrayType& first,
const vtkm::worklet::contourtree_augmented::IdArrayType& second)
: First(first)
, Second(second)
{
}
VTKM_EXEC_CONT
vtkm::Id operator()(const vtkm::Id index) const
{
return First.ReadPortal().Get(index) + Second.ReadPortal().Get(index);
}
private:
vtkm::worklet::contourtree_augmented::IdArrayType First;
vtkm::worklet::contourtree_augmented::IdArrayType Second;
};
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,137 @@
//============================================================================
// 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_augment_boundary_with_necessary_interior_supernodes_append_necessary_supernodes_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_augment_boundary_with_necessary_interior_supernodes_append_necessary_supernodes_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 AugmentBoundaryWithNecessaryInteriorSupernodesAppendNecessarySupernodesWorklet
: public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn supernodes, // input
FieldIn isNecessaryAndInterior, // input
FieldIn boundaryNecessaryId, // input
WholeArrayIn meshSortOrder, // input
WholeArrayOut boundaryIndices, //output
WholeArrayOut bractVertexSuperset // output
);
using ExecutionSignature = void(_1, _2, _3, _4, _5, _6);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
AugmentBoundaryWithNecessaryInteriorSupernodesAppendNecessarySupernodesWorklet(
vtkm::Id numBoundary)
: NumBoundary(numBoundary)
{
}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& supernode,
const bool& isNecessaryAndInterior,
const vtkm::Id boundaryNecessaryId,
const InFieldPortalType meshSortOrderPortal,
const OutFieldPortalType& boundaryIndicesPortal,
const OutFieldPortalType& bractVertexSupersetPortal)
{
// per supernode
if (isNecessaryAndInterior)
{ // if necessary
vtkm::Id sortIndex = vtkm::worklet::contourtree_augmented::MaskedIndex(supernode);
// add to last index in old boundary to find where to put it
vtkm::Id wherePut = this->NumBoundary - 1 + boundaryNecessaryId;
boundaryIndicesPortal.Set(wherePut, sortIndex);
bractVertexSupersetPortal.Set(wherePut, meshSortOrderPortal.Get(sortIndex));
} // if necessary
// In serial this worklet implements the following operation
/*
for (indexType supernode = 0; supernode < contourTree->supernodes.size(); supernode++)
{ // per supernode
if (isNecessaryAndInterior[supernode])
{ // if necessary
indexType sortIndex = maskedIndex(contourTree->supernodes[supernode]);
// add to last index in old boundary to find where to put it
indexType wherePut = nBoundary - 1 + boundaryNecessaryID[supernode];
boundaryIndices[wherePut] = sortIndex;
bractVertexSuperset[wherePut] = mesh->SortOrder(sortIndex);
} // if necessary
} // per supernode
*/
}
private:
vtkm::Id NumBoundary;
}; // AugmentBoundaryWithNecessaryInteriorSupernodesAppendNecessarySupernodesWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -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_bract_maker_augment_boundary_with_necessary_interior_supernodes_unset_boundary_supernodes_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_augment_boundary_with_necessary_interior_supernodes_unset_boundary_supernodes_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 AugmentBoundaryWithNecessaryInteriorSupernodesUnsetBoundarySupernodesWorklet
: public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn boundaryIndices, // input
WholeArrayIn superparents, // input
WholeArrayIn supernodes, // input
WholeArrayOut isNecessaryAndInterior // output
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
AugmentBoundaryWithNecessaryInteriorSupernodesUnsetBoundarySupernodesWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& boundaryVertexSortID,
const InFieldPortalType& superparentsPortal,
const InFieldPortalType& supernodesPortal,
const OutFieldPortalType& isNecessaryAndInteriorPortal)
{
vtkm::Id superparent = superparentsPortal.Get(boundaryVertexSortID);
// if the superparent's supernode is the vertex, they match
if (supernodesPortal.Get(superparent) == boundaryVertexSortID)
{
isNecessaryAndInteriorPortal.Set(superparent, false);
}
// In serial this worklet implements the following operation
/*
for (indexType boundaryVertex = 0; boundaryVertex < nBoundary; boundaryVertex++)
{ // per boundary vertex
indexType boundaryVertexMeshID = bractVertexSuperset[boundaryVertex];
indexType boundaryVertexSortID = boundaryIndices[boundaryVertex];
indexType superparent = contourTree->superparents[boundaryVertexSortID];
// if the superparent's supernode is the vertex, they match
if (contourTree->supernodes[superparent] == boundaryVertexSortID)
isNecessaryAndInterior[superparent] = false;
} // per boundary vertex
*/
}
}; // AugmentBoundaryWithNecessaryInteriorSupernodesUnsetBoundarySupernodesWorklet
} // namespace bract_maker
} // 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_bract_maker_bract_node_comparator_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_bract_node_comparator_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
{
namespace bract_maker
{
// 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;
// constructor - takes vectors as parameters
VTKM_CONT
BRACTNodeComparatorImpl(const IdArrayPortalType& regularIdPortal,
const IdArrayPortalType& meshSortIndexPortal)
: RegularIdPortal(regularIdPortal)
, MeshSortIndexPortal(meshSortIndexPortal)
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
{ // operator()
// retrieve the sort order
vtkm::Id sortIndexI = MeshSortIndexPortal.Get(RegularIdPortal.Get(i));
vtkm::Id sortIndexJ = MeshSortIndexPortal.Get(RegularIdPortal.Get(j));
// now test on that
if (sortIndexI < sortIndexJ)
{
return true;
}
else if (sortIndexJ < sortIndexI)
{
return false;
}
// fallback out of paranoia
return false;
} // operator()
private:
IdArrayPortalType RegularIdPortal;
IdArrayPortalType MeshSortIndexPortal;
}; // BRACTNodeComparatorImpl
/// comparator used to compare hyperarcs for sort
class BRACTNodeComparator : public vtkm::cont::ExecutionObjectBase
{
public:
// constructor - takes vectors as parameters
VTKM_CONT
BRACTNodeComparator(const vtkm::worklet::contourtree_augmented::IdArrayType& regularId,
const vtkm::worklet::contourtree_augmented::IdArrayType& meshSortIndex)
: RegularId(regularId)
, MeshSortIndex(meshSortIndex)
{ // constructor
} // constructor
template <typename DeviceAdapter>
VTKM_CONT BRACTNodeComparatorImpl<DeviceAdapter> PrepareForExecution(
DeviceAdapter device,
vtkm::cont::Token& token) const
{
return BRACTNodeComparatorImpl<DeviceAdapter>(
this->RegularId.PrepareForInput(device, token),
this->MeshSortIndex.PrepareForInput(device, token));
}
private:
vtkm::worklet::contourtree_augmented::IdArrayType RegularId;
vtkm::worklet::contourtree_augmented::IdArrayType MeshSortIndex;
}; // BRACTNodeComparator
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,184 @@
//============================================================================
// 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_boundary_vertices_per_superarc_worklets_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_boundary_vertices_per_superarc_worklets_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
// Step 1of2 for BoundaryRestrictedAugmentedContourTreeMaker<MeshType>::ComputeDependentBoundaryCounts
class BoundaryVerticiesPerSuperArcStepOneWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn boundarySuperparents, // (input)
WholeArrayOut superarcIntrinsicBoundaryCount); // (output) hyperarcs
using ExecutionSignature = void(_1, InputIndex, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
BoundaryVerticiesPerSuperArcStepOneWorklet(vtkm::Id numBoundary)
: NumBoundary(numBoundary)
{
}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const InFieldPortalType& boundarySuperparentsPortal,
const vtkm::Id& boundaryVertex,
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal)
{
if (boundaryVertex == 0)
{
return;
}
vtkm::Id superarcId = boundarySuperparentsPortal.Get(boundaryVertex);
vtkm::Id prevSuperarcId = boundarySuperparentsPortal.Get(boundaryVertex - 1);
// i. Start by detecting the high end of the range
// if they don't match, we're at the beginning of a segment - set the *LOWER* segment's value
if (superarcId != prevSuperarcId)
{
superarcIntrinsicBoundaryCountPortal.Set(prevSuperarcId, boundaryVertex);
}
// ii. Now set the last one explicitly
if (boundaryVertex == (this->NumBoundary - 1))
{
superarcIntrinsicBoundaryCountPortal.Set(superarcId) = this->NumBoundary;
}
// In serial this worklet implements the following operation
/*
for (indexType boundaryVertex = 1; boundaryVertex < nBoundary; boundaryVertex++)
{ // per boundary vertex
indexType superarcID = boundarySuperparents[boundaryVertex];
indexType prevSuperarcID = boundarySuperparents[boundaryVertex-1];
// if they don't match, we're at the beginning of a segment - set the *LOWER* segment's value
if (superarcID != prevSuperarcID)
superarcIntrinsicBoundaryCount[prevSuperarcID] = boundaryVertex;
} // per boundary vertex
superarcIntrinsicBoundaryCount[boundarySuperparents[nBoundary-1]] = nBoundary;
*/
}
private:
vtkm::Id NumBoundary;
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
// Step 1of2 for BoundaryRestrictedAugmentedContourTreeMaker<MeshType>::ComputeDependentBoundaryCounts
class BoundaryVerticiesPerSuperArcStepTwoWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn boundarySuperparents, // (input)
WholeArrayOut superarcIntrinsicBoundaryCount); // (output) hyperarcs
using ExecutionSignature = void(_1, InputIndex, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
BoundaryVerticiesPerSuperArcStepTwoWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const InFieldPortalType& boundarySuperparentsPortal,
const vtkm::Id& boundaryVertex,
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal)
{
if (boundaryVertex == 0)
{
return;
}
vtkm::Id superarcId = boundarySuperparentsPortal.Get(boundaryVertex);
vtkm::Id prevSuperarcId = boundarySuperparentsPortal.Get(boundaryVertex - 1);
// i. Start by detecting the high end of the range
// if they don't match, we're at the beginning of a segment - set the *LOWER* segment's value
if (superarcId != prevSuperarcId)
{
superarcIntrinsicBoundaryCountPortal.Set(
superarcId, superarcIntrinsicBoundaryCountPortal.Get(superarcId) - boundaryVertex);
}
// In serial this worklet implements the following operation
/*
for (indexType boundaryVertex = 1; boundaryVertex < nBoundary; boundaryVertex++)
{ // per boundary vertex
indexType superarcID = boundarySuperparents[boundaryVertex];
indexType prevSuperarcID = boundarySuperparents[boundaryVertex-1];
// if they don't match, we're at the beginning of a segment - set the *LOWER* segment's value
if (superarcID != prevSuperarcID)
superarcIntrinsicBoundaryCount[superarcID] -= boundaryVertex;
} // per boundary vertex
*/
}
}; // BoundaryVerticiesPerSuperArcStepTwoWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,40 @@
##============================================================================
## 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
BoundaryVerticesPerSuperArcWorklets.h
PropagateBoundaryCountsSubtractDependentCountsWorklet.h
PropagateBoundaryCountsTransferDependentCountsWorklet.h
PropagateBoundaryCountsTransferCumulativeCountsWorklet.h
PropagateBoundaryCountsComputeGroupTotalsWorklet.h
FindNecessaryInteriorSupernodesFindNodesWorklet.h
FindNecessaryInteriorSetSuperparentNecessaryWorklet.h
AugmentBoundaryWithNecessaryInteriorSupernodesUnsetBoundarySupernodesWorklet.h
AugmentBoundaryWithNecessaryInteriorSupernodesAppendNecessarySupernodesWorklet.h
FindBractSuperarcsSuperarcToWorklet.h
SetUpAndDownNeighboursWorklet.h
IdentifyRegularisedSupernodesStepOneWorklet.h
IdentifyRegularisedSupernodesStepTwoWorklet.h
AddTerminalFlagsToUpDownNeighboursWorklet.h
PointerDoubleUpDownNeighboursWorklet.h
CompressRegularisedNodesCopyNecessaryRegularNodesWorklet.h
CompressRegularisedNodesFindNewSuperarcsWorklet.h
CompressRegularisedNodesResolveRootWorklet.h
CompressRegularisedNodesTransferVerticesWorklet.h
CompressRegularisedNodesFillBractSuperarcsWorklet.h
ArraySumFunctor.h
NoSuchElementFunctor.h
SelectRangeFunctor.h
HyperarcComparator.h
ContourTreeNodeHyperArcComparator.h
BRACTNodeComparator.h
)
vtkm_declare_headers(${headers})

@ -0,0 +1,102 @@
//============================================================================
// 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_compress_regularised_nodes_copy_necessary_regular_nodes_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_copy_necessary_regular_nodes_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class CompressRegularisedNodesCopyNecessaryRegularNodesWorklet
: public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldInOut newVertexId, // Input/Output
FieldIn keptInBract // input
);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
CompressRegularisedNodesCopyNecessaryRegularNodesWorklet() {}
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& newVertexIdIn, const vtkm::Id& keptInBract)
{
return (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn)) ? (keptInBract - 1)
: newVertexIdIn;
// In serial this worklet implements the following operation
/*
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
if (!noSuchElement(newVertexID[returnIndex]))
newVertexID[returnIndex] = keptInBract[returnIndex]-1;
*/
}
}; // CompressRegularisedNodesCopyNecessaryRegularNodesWorklet
} // namespace bract_maker
} // 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_bract_maker_compress_regularised_nodes_fill_bract_superarcs_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_fill_bract_superarcs_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class CompressRegularisedNodesFillBractSuperarcsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn newSuperarc,
WholeArrayIn reverseSorter,
FieldIn vertexSorter,
FieldOut bractSuperarcs);
using ExecutionSignature = void(_1, _2, _3);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
CompressRegularisedNodesFillBractSuperarcsWorklet() {}
template <typename InFieldPortalType>
VTKM_EXEC vtkm::Id operator()(const InFieldPortalType newSuperarcPortal,
const InFieldPortalType reverseSorterPortal,
const vtkm::Id& vertexSorterIndex)
{
vtkm::Id newSuperarcIndex = newSuperarcPortal.Get(vertexSorterIndex);
if (vtkm::worklet::contourtree_augmented::NoSuchElement(newSuperarcIndex))
{
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
else
{
return reverseSorterPortal.Get(newSuperarcIndex);
}
// In serial this worklet implements the following operation
/*
for (indexType bractID = 0; bractID < newSuperarc.size(); bractID++)
{ // per bract node
// do the same for the superarc, testing for NO_SUCH_ELEMENT
if (noSuchElement(newSuperarc[vertexSorter[bractID]]))
bract->superarcs[bractID] = NO_SUCH_ELEMENT;
else
bract->superarcs[bractID] = reverseSorter[newSuperarc[vertexSorter[bractID]]];
} // per bract node
*/
}
}; // CompressRegularisedNodesFillBractSuperarcsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,186 @@
//============================================================================
// 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_compress_regularised_nodes_find_new_superarcs_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_find_new_superarcs_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class CompressRegularisedNodesFindNewSuperarcsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn newVertexId, // Input
FieldIn bractSuperarcs, // input
WholeArrayIn upNeighbour, //input
WholeArrayIn downNeighbour,
WholeArrayOut newSuperarc // output
);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
CompressRegularisedNodesFindNewSuperarcsWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& returnIndex,
const InFieldPortalType& newVertexIdPortal,
const vtkm::Id& bractSuperarcIdIn,
const InFieldPortalType& downNeighbourPortal,
const InFieldPortalType& upNeighbourPortal,
const OutFieldPortalType& newSuperarcPortal)
{
// per vertex
// skip all unnecessary vertices
vtkm::Id newVertexIdIn = newVertexIdPortal.Get(returnIndex);
if (vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn))
{
return;
}
// retrieve the new ID
vtkm::Id newId = newVertexIdIn;
// for necessary vertices, look at the superarc
vtkm::Id oldInbound = bractSuperarcIdIn;
// i. points to nothing - copy it
if (vtkm::worklet::contourtree_augmented::NoSuchElement((oldInbound)))
{
newSuperarcPortal.Set(newId, (vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT));
}
// ii. points to a necessary vertex - copy it
else if (!vtkm::worklet::contourtree_augmented::NoSuchElement(
newVertexIdPortal.Get(oldInbound)))
{
newSuperarcPortal.Set(newId, newVertexIdPortal.Get(oldInbound));
}
// iii. points to an unnecessary vertex
else
{ // points to an unnecessary vertex
// check the old up neighbour
vtkm::Id upNbr =
vtkm::worklet::contourtree_augmented::MaskedIndex(upNeighbourPortal.Get(oldInbound));
vtkm::Id downNbr =
vtkm::worklet::contourtree_augmented::MaskedIndex(downNeighbourPortal.Get(oldInbound));
// if it's us, we've got a downwards inbound arc
// and the down neighbour holds the right new superarc
if (upNbr == returnIndex)
{
newSuperarcPortal.Set(newId, newVertexIdPortal.Get(downNbr));
}
// otherwise the up neighbour does
else
{
newSuperarcPortal.Set(newId, newVertexIdPortal.Get(upNbr));
}
} // points to an unnecessary vertex
// In serial this worklet implements the following operation
/*
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
{ // per vertex
// skip all unnecessary vertices
if (noSuchElement(newVertexID[returnIndex]))
continue;
// retrieve the new ID
indexType newID = newVertexID[returnIndex];
// for necessary vertices, look at the superarc
indexType oldInbound = bract->superarcs[returnIndex];
// i. points to nothing - copy it
if (noSuchElement(oldInbound))
newSuperarc[newID] = NO_SUCH_ELEMENT;
// ii. points to a necessary vertex - copy it
else if (!noSuchElement(newVertexID[oldInbound]))
newSuperarc[newID] = newVertexID[oldInbound];
// iii. points to an unnecessary vertex
else
{ // points to an unnecessary vertex
// check the old up neighbour
indexType upNbr = maskedIndex(upNeighbour[oldInbound]);
indexType downNbr = maskedIndex(downNeighbour[oldInbound]);
// if it's us, we've got a downwards inbound arc
// and the down neighbour holds the right new superarc
if (upNbr == returnIndex)
newSuperarc[newID] = newVertexID[downNbr];
// otherwise the up neighbour does
else
newSuperarc[newID] = newVertexID[upNbr];
} // points to an unnecessary vertex
} // per vertex
*/
}
}; // CompressRegularisedNodesFindNewSuperarcsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,136 @@
//============================================================================
// 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_compress_regularised_nodes_resolve_root_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_resolve_root_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class CompressRegularisedNodesResolveRootWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn newIndex, // input
WholeArrayInOut newSuperarc // input/output
);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
CompressRegularisedNodesResolveRootWorklet() {}
template <typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& newIndex, const InOutFieldPortalType& newSuperarcPortal)
{
// per kept vertex
// retrieve it to register
vtkm::Id newInbound = newSuperarcPortal.Get(newIndex);
// if it doesn't exist, do nothing
if (vtkm::worklet::contourtree_augmented::NoSuchElement(newInbound))
{
return;
}
// if there is no loopback, do nothing
if (newSuperarcPortal.Get(newInbound) != newIndex)
{
return;
}
// if there is loopback and we're the lower one, substitute NULL
if (newIndex < newInbound)
{
newSuperarcPortal.Set(newIndex, vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
}
// In serial this worklet implements the following operation
/*
for (indexType newIndex = 0; newIndex < nKept; newIndex++)
{ // per kept vertex
// retrieve it to register
indexType newInbound = newSuperarc[newIndex];
// if it doesn't exist, do nothing
if (noSuchElement(newInbound))
continue;
// if there is no loopback, do nothing
if (newSuperarc[newInbound] != newIndex)
continue;
// if there is loopback and we're the lower one, substitute NULL
if (newIndex < newInbound)
newSuperarc[newIndex] = NO_SUCH_ELEMENT;
} // per kept vertex
*/
}
}; // CompressRegularisedNodesResolveRootWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,103 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_transfer_vertices_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_compress_regularised_nodes_transfer_vertices_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class CompressRegularisedNodesTransferVerticesWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn bractVertexSuperset, // input
FieldIn newVertexId, // input
FieldOut newVertexIndex);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
CompressRegularisedNodesTransferVerticesWorklet() {}
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& bractVertexSupersetIndex,
const vtkm::Id& newVertexIdIn)
{
return (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn))
? bractVertexSupersetIndex
: 0;
// In serial this worklet implements the following operation
/*
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
if (!noSuchElement(newVertexID[returnIndex]))
newVertexIndex[newVertexID[returnIndex]] = bractVertexSuperset[returnIndex];
*/
}
}; // CompressRegularisedNodesTransferVerticesWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,166 @@
//============================================================================
// 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_contourtree_node_hyperarc_comperator_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_contourtree_node_hyperarc_comperator_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace ctaug = vtkm::worklet::contourtree_augmented;
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
// device implementation of the ContourTreeNodeHyperArcComparator
template <typename DeviceAdapter>
class ContourTreeNodeHyperArcComparatorImpl
{
public:
using IdArrayPortalType =
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst;
// constructor - takes vectors as parameters
VTKM_CONT
ContourTreeNodeHyperArcComparatorImpl(const IdArrayPortalType& superarcsPortal,
const IdArrayPortalType& superparentsPortal)
: SuperarcsPortal(superarcsPortal)
, SuperparentsPortal(superparentsPortal)
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
{ // operator()
// retrieve the left & right superparents
vtkm::Id leftSuperparent = this->SuperparentsPortal.Get(ctaug::MaskedIndex(i));
vtkm::Id rightSuperparent = this->SuperparentsPortal.Get(ctaug::MaskedIndex(j));
// compare the superparents
if (ctaug::MaskedIndex(leftSuperparent) < ctaug::MaskedIndex(rightSuperparent))
{
return true;
}
if (ctaug::MaskedIndex(leftSuperparent) > ctaug::MaskedIndex(rightSuperparent))
{
return false;
}
// parents are equal, so retrieve superarc for ascending flag & compare indices
// TODO We masked the leftSuperparent here. Check if we need to do this or not
bool ascentFlag =
ctaug::IsAscending(this->SuperarcsPortal.Get(ctaug::MaskedIndex(leftSuperparent)));
// compare the sort indices, flipping based on ascending index from superparent
if (i < j)
{
return ascentFlag;
}
else if (i > j)
{
return !ascentFlag;
}
else
{
return false;
}
} // operator()
private:
IdArrayPortalType SuperarcsPortal;
IdArrayPortalType SuperparentsPortal;
}; // ContourTreeNodeHyperArcComparatorImpl
/// comparator to use for sorting nodes by hyperparent (i.e. amalgamates augmentation & sorting)
/// for this one, we don't care (yet) about *WHEN* they were transferred
/// The original version of this took the sortIndex array, but it turns out that it only gets used
/// on an array that already contains sortIndex, and this simplifies code elsewhere, so I have removed it
class ContourTreeNodeHyperArcComparator : public vtkm::cont::ExecutionObjectBase
{
public:
// constructor - takes vectors as parameters
VTKM_CONT
ContourTreeNodeHyperArcComparator(const ctaug::IdArrayType superarcs,
const ctaug::IdArrayType superparents)
: Superarcs(superarcs)
, Superparents(superparents)
{ // constructor
} // constructor
template <typename DeviceAdapter>
VTKM_CONT ContourTreeNodeHyperArcComparatorImpl<DeviceAdapter> PrepareForExecution(
DeviceAdapter device,
vtkm::cont::Token& token) const
{
return ContourTreeNodeHyperArcComparatorImpl<DeviceAdapter>(
this->Superarcs.PrepareForInput(device, token),
this->Superparents.PrepareForInput(device, token));
}
private:
ctaug::IdArrayType Superarcs;
ctaug::IdArrayType Superparents;
}; // ContourTreeNodeHyperArcComparator
} // namespace bract_maker
} // namespace contourtree_distributes
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,253 @@
//============================================================================
// 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_find_bract_superacrs_superarc_to_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_find_bract_superacrs_superarc_to_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Compute the superarc "to" for every bract node
/// Part of the BoundaryRestrictedAugmentedContourTree.FindBractSuperarcs function
class FindBractSuperarcsSuperarcToWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn bractVertexSuperset, // input
WholeArrayIn boundaryIndices, // input
WholeArrayIn boundaryTreeId, // input
WholeArrayIn contourtreeSuperparents, // input
WholeArrayIn contourtreeHyperparents, // input
WholeArrayIn contourtreeHyperarcs, // input
WholeArrayIn contourtreeSupernodes, // input
WholeArrayIn meshSortOrder, // input
WholeArrayOut treeToSuperset, // output
FieldOut bractSuperarcs // output
);
using ExecutionSignature = _10(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
FindBractSuperarcsSuperarcToWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& from,
const InFieldPortalType& bractVertexSupersetPortal,
const InFieldPortalType& boundaryIndicesPortal,
const InFieldPortalType& boundaryTreeIdPortal,
const InFieldPortalType& contourtreeSuperparentsPortal,
const InFieldPortalType& contourtreeHyperparentsPortal,
const InFieldPortalType& contourtreeHyperarcsPortal,
const InFieldPortalType& contourtreeSupernodesPortal,
const InFieldPortalType& meshSortOrderPortal,
const OutFieldPortalType& treeToSupersetPortal)
{
// find the sort order, super- and hyper- parent
// vtkm::Id fromIndex = bractVertexSupersetPortal.Get(from);
vtkm::Id fromSort = boundaryIndicesPortal.Get(from);
vtkm::Id fromSuper = contourtreeSuperparentsPortal.Get(fromSort);
vtkm::Id fromHyper = contourtreeHyperparentsPortal.Get(fromSuper);
// also allocate space for the from, with index, &c.
vtkm::Id to = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
vtkm::Id toIndex = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
vtkm::Id toSort = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
vtkm::Id toSuper = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
vtkm::Id toHyper = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// for any vertex OTHER than the one at the RHE, set these variables
if (from != bractVertexSupersetPortal.GetNumberOfValues() - 1)
{ // not RHE
to = from + 1;
toIndex = bractVertexSupersetPortal.Get(to);
toSort = boundaryIndicesPortal.Get(to);
toSuper = contourtreeSuperparentsPortal.Get(toSort);
toHyper = contourtreeHyperparentsPortal.Get(toSuper);
} // not RHE
// while we are here, we want to establish the mapping from the contour tree ID to the superset ID
// so we test whether the node is a supernode, by seeing if it's sort ID matches its superparent
// In the original code this was done last. We do this here first, because the values for
// bractSuperarcs are set by return statements, so we don't reach the end of the function
// and reordering the operation should be no problem.
if (contourtreeSupernodesPortal.Get(fromSuper) == fromSort)
{ // supernode
treeToSupersetPortal.Set(fromSuper, from);
} // supernode
// the easy case - there is a "hyper-neighbour" to link to
if (fromHyper == toHyper)
{ // hyperparents match
return to; // same as bractSuperarcs.WritePortal().Set(from, to);
} // hyperparents match
// the rest: we're at the RHE of a hyperarc and need to connect onwards
else
{ // hyperparents do not match
// retrieve the hypertarget
vtkm::Id hyperTarget = contourtreeHyperarcsPortal.Get(fromHyper);
// if it's non-existent, we're at the root, in which case our from vertex becomes the root
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hyperTarget))
{ // root vertex
// same as bractSuperarcs.WritePortal().Set(from, NO_SUCH_ELEMENT)
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
} // root vertex
// otherwise it points to a supernode
else
{ // not root vertex
// check whether the target will be in the BRACT
vtkm::Id regularTargetId = meshSortOrderPortal.Get(contourtreeSupernodesPortal.Get(
vtkm::worklet::contourtree_augmented::MaskedIndex(hyperTarget)));
// now look up the ID in the BRACT
vtkm::Id bract_id = boundaryTreeIdPortal.Get(regularTargetId);
// if it is not in the tree, then this node becomes the root
if (vtkm::worklet::contourtree_augmented::NoSuchElement(bract_id))
{
// same as bractSuperarcs.WritePortal().Set(from, NO_SUCH_ELEMENT)
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
// otherwise, we use the ID just retrieved
else
{
// same as // same as bractSuperarcs.WritePortal().Set(from, bract_it)
return bract_id;
}
} // not root vertex
} // hyperparents do not match
// In serial this worklet implements the following operation
/*
for (indexType from = 0; from < bractVertexSuperset.size(); from++)
{ // per vertex in boundary tree
// find the sort order, super- and hyper- parent
indexType fromIndex = bractVertexSuperset[from], fromSort = boundaryIndices[from];
indexType fromSuper = contourTree->superparents[fromSort], fromHyper = contourTree->hyperparents[fromSuper];
// also allocate space for the from, with index, &c.
indexType to = NO_SUCH_ELEMENT, toIndex = NO_SUCH_ELEMENT, toSort = NO_SUCH_ELEMENT;
indexType toSuper = NO_SUCH_ELEMENT, toHyper = NO_SUCH_ELEMENT;
// for any vertex OTHER than the one at the RHE, set these variables
if (from != bractVertexSuperset.size() - 1)
{ // not RHE
to = from + 1;
toIndex = bractVertexSuperset[to];
toSort = boundaryIndices[to];
toSuper = contourTree->superparents[toSort];
toHyper = contourTree->hyperparents[toSuper];
} // not RHE
// the easy case - there is a "hyper-neighbour" to link to
if (fromHyper == toHyper)
{ // hyperparents match
bract->superarcs[from] = to;
} // hyperparents match
else
// the rest: we're at the RHE of a hyperarc and need to connect onwards
{ // hyperparents do not match
// retrieve the hypertarget
indexType hyperTarget = contourTree->hyperarcs[fromHyper];
// if it's non-existent, we're at the root, in which case our from vertex becomes the root
if (noSuchElement(hyperTarget))
{ // root vertex
bract->superarcs[from] = NO_SUCH_ELEMENT;
} // root vertex
// otherwise it points to a supernode
else
{ // not root vertex
// check whether the target will be in the BRACT
indexType regularTargetID = mesh->SortOrder(contourTree->supernodes[maskedIndex(hyperTarget)]);
// now look up the ID in the BRACT
indexType BRACTID = boundaryTreeID[regularTargetID];
// if it is not in the tree, then this node becomes the root
if (noSuchElement(BRACTID))
bract->superarcs[from] = NO_SUCH_ELEMENT;
// otherwise, we use the ID just retrieved
else
bract->superarcs[from] = BRACTID;
} // not root vertex
} // hyperparents do not match
// while we are here, we want to establish the mapping from the contour tree ID to the superset ID
// so we test whether the node is a supernode, by seeing if it's sort ID matches its superparent
if (contourTree->supernodes[fromSuper] == fromSort)
{ // supernode
tree2Superset[fromSuper] = from;
} // supernode
} // per vertex in boundary tree
*/
} // operator()()
}; // FindBractSuperarcsSuperarcToWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,133 @@
//============================================================================
// 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_find_necessary_interior_supernodes_set_superparent_necessary_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_find_necessary_interior_supernodes_set_superparent_necessary_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 FindNecessaryInteriorSetSuperparentNecessaryWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn boundaryIndices, // (input)
WholeArrayIn superparents, // (input)
WholeArrayIn superarcs, // (input)
WholeArrayOut isNecessary // (output)
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
FindNecessaryInteriorSetSuperparentNecessaryWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& boundaryIndex,
const InFieldPortalType superparentsPortal,
const InFieldPortalType superarcsPortal,
const OutFieldPortalType& isNecessaryPortal)
{
// per boundary node
// find the superparent
vtkm::Id superparent =
vtkm::worklet::contourtree_augmented::MaskedIndex(superparentsPortal.Get(boundaryIndex));
// make it necessary
isNecessaryPortal.Set(superparent, true);
// retrieve the supertarget
vtkm::Id supertarget = superarcsPortal.Get(superparent);
// check for NULL ness & set the target as well if it exists
if (vtkm::worklet::contourtree_augmented::NoSuchElement(supertarget))
{
return;
}
// set the target as well
isNecessaryPortal.Set(vtkm::worklet::contourtree_augmented::MaskedIndex(supertarget), true);
// In serial this worklet implements the following operation
/*
for (indexType boundaryNode = 0; boundaryNode < boundaryIndices.size(); boundaryNode++)
{ // per boundary node
// find the superparent
indexType superparent = maskedIndex(contourTree->superparents[boundaryIndices[boundaryNode]]);
// make it necessary
isNecessary[superparent] = true;
// retrieve the supertarget
indexType supertarget = contourTree->superarcs[superparent];
// check for NULL ness & set the target as well if it exists
if (noSuchElement(supertarget))
continue;
// set the target as well
isNecessary[maskedIndex(supertarget)] = true;
} // per boundary node
*/
}
}; // FindNecessaryInteriorSetSuperparentNecessaryWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,134 @@
//============================================================================
// 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_find_necessary_interior_supernodes_find_nodes_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_find_necessary_interior_supernodes_find_nodes_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// 1.B. Our condition is that if the superarc dependent count is neither 0 nor the # of boundary
/// points, the superarc target is necessary. Note that there may be write conflicts, but it's
/// an OR operation, so it doesn't matter
/// Part of the BoundaryRestrictedAugmentedContourTree.FindNecessaryInteriorSupernodes function
class FindNecessaryInteriorSupernodesFindNodesWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn superarc, // (input) superarcs
FieldIn superarcDependentBoundaryCount, // (input)
WholeArrayOut isNecessary // (output)
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
FindNecessaryInteriorSupernodesFindNodesWorklet(vtkm::Id numBoundary)
: NumBoundary(numBoundary)
{
}
template <typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& superarc,
const vtkm::Id& dependentWeight,
const OutFieldPortalType& isNecessaryPortal)
{
// skip the stub superarc at the root
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarc))
{
return;
}
// skip vertices with 0 / ALL
if ((dependentWeight != 0) && (dependentWeight != this->NumBoundary))
{ // mark target
isNecessaryPortal.Set(vtkm::worklet::contourtree_augmented::MaskedIndex(superarc), true);
} // mark target
// In serial this worklet implements the following operation
/*
for (indexType supernode = 0; supernode < contourTree->supernodes.size(); supernode++)
{ // per supernode
// skip the stub superarc at the root
if (noSuchElement(contourTree->superarcs[supernode]))
continue;
indexType dependentWeight = superarcDependentBoundaryCount[supernode];
// skip vertices with 0 / ALL
if ((dependentWeight != 0) && (dependentWeight != nBoundary))
// mark the target
{ // mark target
isNecessary[maskedIndex(contourTree->superarcs[supernode])] = true;
} // mark target
} // per supernode
*/
}
private:
vtkm::Id NumBoundary;
}; // FindNecessaryInteriorSupernodesFindNodesWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,125 @@
//============================================================================
// 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_hyperarc_comparator_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_hyperarc_comparator_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
{
namespace bract_maker
{
// device implementation of the comparator used for sorting hyperarcs
template <typename DeviceAdapter>
class HyperarcComparatorImpl
{
public:
using IdArrayPortalType =
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst;
// constructor - takes vectors as parameters
VTKM_CONT
HyperarcComparatorImpl(const IdArrayPortalType& hyperarcsPortal)
: HyperarcsPortal(hyperarcsPortal)
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
{ // operator()
return vtkm::worklet::contourtree_augmented::MaskedIndex(HyperarcsPortal.Get(i)) <
vtkm::worklet::contourtree_augmented::MaskedIndex(HyperarcsPortal.Get(j));
} // operator()
private:
IdArrayPortalType HyperarcsPortal;
}; // HyperarcComparatorImpl
/// comparator used to compare hyperarcs for sort
class HyperarcComparator : public vtkm::cont::ExecutionObjectBase
{
public:
// constructor - takes vectors as parameters
VTKM_CONT
HyperarcComparator(const vtkm::worklet::contourtree_augmented::IdArrayType hyperarcs)
: Hyperarcs(hyperarcs)
{ // constructor
} // constructor
template <typename DeviceAdapter>
VTKM_CONT HyperarcComparatorImpl<DeviceAdapter> PrepareForExecution(
DeviceAdapter device,
vtkm::cont::Token& token) const
{
return HyperarcComparatorImpl<DeviceAdapter>(this->Hyperarcs.PrepareForInput(device, token));
}
private:
vtkm::cont::ArrayHandle<vtkm::Id> Hyperarcs;
}; // HyperarcComparator
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,168 @@
//============================================================================
// 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_identify_regularise_supernodes_step_one_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_identify_regularise_supernodes_step_one_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class IdentifyRegularisedSupernodesStepOneWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn bractVertexSuperset, // input
FieldIn bractSuperarcs, // input
WholeArrayIn meshSortIndex, // input
WholeArrayIn upNeighbour, // input
WholeArrayIn downNeighbour, // input
WholeArrayOut newVertexId // output
);
using ExecutionSignature = void(InputIndex, _2, _1, _3, _4, _5, _6);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
IdentifyRegularisedSupernodesStepOneWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& from,
const vtkm::Id& to,
const InFieldPortalType& bractVertexSupersetPortal,
const InFieldPortalType& meshSortIndexPortal,
const InFieldPortalType& upNeighbourPortal,
const InFieldPortalType& downNeighbourPortal,
const OutFieldPortalType& newVertexIdPortal)
{
// per vertex
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
{
return;
}
// now find the sort index of the from and to
vtkm::Id fromSort = meshSortIndexPortal.Get(bractVertexSupersetPortal.Get(from));
vtkm::Id toSort = meshSortIndexPortal.Get(bractVertexSupersetPortal.Get(to));
// use this to identify direction of edge
if (fromSort < toSort)
{ // from is lower
if (upNeighbourPortal.Get(from) != to)
{
newVertexIdPortal.Set(from, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
if (downNeighbourPortal.Get(to) != from)
{
newVertexIdPortal.Set(to, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
} // from is lower
else
{ // to is lower
if (upNeighbourPortal.Get(to) != from)
{
newVertexIdPortal.Set(to, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
if (downNeighbourPortal.Get(from) != to)
{
newVertexIdPortal.Set(from, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
} // to is lower
// In serial this worklet implements the following operation
/*
for (indexType from = 0; from < bractVertexSuperset.size(); from++)
{ // per vertex
indexType to = bract->superarcs[from];
// ignore the last terminating edge
if (noSuchElement(to))
continue;
// now find the sort index of the from and to
indexType fromSort = mesh->SortIndex(bractVertexSuperset[from]);
indexType toSort = mesh->SortIndex(bractVertexSuperset[to]);
// use this to identify direction of edge
if (fromSort < toSort)
{ // from is lower
if (upNeighbour[from] != to)
newVertexID[from] = ELEMENT_EXISTS;
if (downNeighbour[to] != from)
newVertexID[to] = ELEMENT_EXISTS;
} // from is lower
else
{ // to is lower
if (upNeighbour[to] != from)
newVertexID[to] = ELEMENT_EXISTS;
if (downNeighbour[from] != to)
newVertexID[from] = ELEMENT_EXISTS;
} // to is lower
} // per vertex
*/
}
}; // IdentifyRegularisedSupernodesStepOneWorklet
} // namespace bract_maker
} // 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_bract_maker_identify_regularise_supernodes_step_two_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_identify_regularise_supernodes_step_two_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
/// Step 2 of IdentifyRegularisedSupernodes
/// We also want to flag the leaves and boundary nodes as necessary
class IdentifyRegularisedSupernodesStepTwoWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn bractVertexSuperset, // input
FieldIn upNeighbour, // input
FieldIn downNeighbour, // input
ExecObject meshBoundary, // input
WholeArrayOut newVertexId // output
);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
IdentifyRegularisedSupernodesStepTwoWorklet() {}
template <typename InFieldPortalType, 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)
{
// per vertex
// check for leaf criticality
if (vtkm::worklet::contourtree_augmented::NoSuchElement(upNeighbourValue) ||
vtkm::worklet::contourtree_augmented::NoSuchElement(downNeighbourValue))
{
newVertexIdPortal.Set(boundaryNode, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
// retrieve mesh index (i.e., bractVertexSupersetValue) & check whether on the boundary
if (meshBoundary.liesOnBoundary(bractVertexSupersetValue))
{
newVertexIdPortal.Set(boundaryNode, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
}
// In serial this worklet implements the following operation
/*
for (indexType boundaryNode = 0; boundaryNode < bractVertexSuperset.size(); boundaryNode++)
{ // per vertex
// check for leaf criticality
if (noSuchElement(upNeighbour[boundaryNode]) || noSuchElement(downNeighbour[boundaryNode]))
newVertexID[boundaryNode] = ELEMENT_EXISTS;
// retrieve mesh index & check whether on the boundary
indexType meshIndex = bractVertexSuperset[boundaryNode];
if (mesh->liesOnBoundary(meshIndex))
newVertexID[boundaryNode] = ELEMENT_EXISTS;
} // per vertex
*/
}
}; // IdentifyRegularisedSupernodesStepTwoWorklet
} // namespace bract_maker
} // 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_bract_maker_no_such_element_functor_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_no_such_element_functor_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
//Simple functor to subset a VTKm ArrayHandle
class NoSuchElementFunctor
{
public:
VTKM_EXEC_CONT
NoSuchElementFunctor(){};
VTKM_EXEC_CONT
vtkm::Id operator()(const vtkm::Id value) const
{
return static_cast<vtkm::Id>(!vtkm::worklet::contourtree_augmented::NoSuchElement(value));
}
private:
};
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,129 @@
//============================================================================
// 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_pointer_double_up_down_neighbours_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_pointer_double_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 bract_maker
{
/// Step 1 of IdentifyRegularisedSupernodes
class PointerDoubleUpDownNeighboursWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayInOut upNeighbour, // input/output
WholeArrayInOut downNeighbour // input/output
);
using ExecutionSignature = void(InputIndex, _1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
PointerDoubleUpDownNeighboursWorklet() {}
template <typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id* returnIndex,
const InOutFieldPortalType& upNeighbourPortal,
const InOutFieldPortalType& downNeighbourPortal)
{
// per vertex
// retrieve nbr & see if it's terminal
vtkm::Id upNbr = upNeighbourPortal.Get(returnIndex);
// otherwise jump
if (!vtkm::worklet::contourtree_augmented::IsTerminalElement(upNbr))
{
upNeighbourPortal.Set(returnIndex, upNeighbourPortal.Get(upNbr));
}
// retrieve nbr & see if it's terminal
vtkm::Id dnNbr = downNeighbourPortal.Get(returnIndex);
// otherwise jump
if (!vtkm::worklet::contourtree_augmented::IsTerminalElement(dnNbr))
{
downNeighbourPortal.Set(returnIndex, downNeighbourPortal.Get(dnNbr));
}
// In serial this worklet implements the following operation
/*
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
{ // per vertex
// retrieve nbr & see if it's terminal
indexType upNbr = upNeighbour[returnIndex];
// otherwise jump
if (!isTerminalElement(upNeighbour[returnIndex]))
upNeighbour[returnIndex] = upNeighbour[upNbr];
// retrieve nbr & see if it's terminal
indexType dnNbr = downNeighbour[returnIndex];
// otherwise jump
if (!isTerminalElement(downNeighbour[returnIndex]))
downNeighbour[returnIndex] = downNeighbour[dnNbr];
} // per vertex
*/
}
}; // PointerDoubleUpDownNeighboursWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,149 @@
//============================================================================
// 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_propagate_boundary_counts_compute_group_totals_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_propagate_boundary_counts_compute_group_totals_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 subtract the beginning of the group to get the total for each group
/// Part of the BoundaryRestrictedAugmentedContourTree.PropagateBoundaryCounts function
///
/// 5. Finally, we subtract the beginning of the group to get the total for each group
class PropagateBoundaryCountsComputeGroupTotalsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
WholeArrayIn hyperarcTargetSortPermutation, // (input)
WholeArrayIn hyperarcs, // (input) contour tree hyperarcs
WholeArrayIn accumulatedBoundaryCountPortal, // (input)
WholeArrayInOut supernodeTransferBoundaryCountPortal // (input/output)
);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
PropagateBoundaryCountsComputeGroupTotalsWorklet() {}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hyperarc,
const InFieldPortalType& hyperarcTargetSortPermutationPortal,
const InFieldPortalType& hyperarcsPortal,
const InFieldPortalType& accumulatedBoundaryCountPortal,
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal)
{
// the prefix sum of the first element is the correct value anyway so we can ignore it
if (hyperarc == 0)
{
return;
}
// retrieve the hypertarget & the previous one as well
vtkm::Id hyperarcTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(
hyperarcsPortal.Get(hyperarcTargetSortPermutationPortal.Get(hyperarc)));
vtkm::Id prevHyperarcTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(
hyperarcsPortal.Get(hyperarcTargetSortPermutationPortal.Get(hyperarc - 1)));
// if they differ, write
if (hyperarcTarget != prevHyperarcTarget)
{ // they're different
// if it's not the last one, transfer it to the supernode at the far end
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(hyperarcTarget))
{ // valid target
supernodeTransferBoundaryCountPortal.Set(
hyperarcTarget,
supernodeTransferBoundaryCountPortal.Get(hyperarcTarget) -
accumulatedBoundaryCountPortal.Get(hyperarc - 1));
} // valid target
} // they're different
// In serial this worklet implements the following operation
/*
// NOTE: in contrast to the original imlementation this worklet starts the iteration at
// 0 for simplicity, hence, we need to check this case separately here
for (vtkm::Id hyperarc = 1; hyperarc < hyperarcTargetSortPermutation.size(); hyperarc++)
{ // per hyperarc
// retrieve the hypertarget & the previous one as well
vtkm::Id hyperarcTarget = maskedIndex(contourTree->hyperarcs[hyperarcTargetSortPermutation[hyperarc]]);
vtkm::Id prevHyperarcTarget = maskedIndex(contourTree->hyperarcs[hyperarcTargetSortPermutation[hyperarc-1]]);
// if they differ, write
if (hyperarcTarget != prevHyperarcTarget)
{ // they're different
// if it's not the last one, transfer it to the supernode at the far end
if (! noSuchElement(hyperarcTarget))
{ // valid target
supernodeTransferBoundaryCount[hyperarcTarget] -= accumulatedBoundaryCount[hyperarc-1];
} // valid target
} // they're different
} // per hyperarc
*/
}
}; // PropagateBoundaryCountsComputeGroupTotalsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -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_bract_maker_propagate_boundary_counts_subtract_dependent_counts_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_propagate_boundary_counts_subtract_dependent_counts_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 Subtract out the dependent count of the prefix to the entire hyperarc
/// Part of the BoundaryRestrictedAugmentedContourTree.PropagateBoundaryCounts function
class PropagateBoundaryCountsSubtractDependentCountsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn supernodeIndex, // (input) index of supernodes for iteration
WholeArrayIn hyperparents, // (input) contour tree hyperparents
WholeArrayIn hypernodes, // (input) contour tree hypernodes
WholeArrayIn superarcDependentBoundaryCount, // (input)
WholeArrayInOut newSuperArcDependentBoundaryCount // (input/output)
);
using ExecutionSignature = void(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
PropagateBoundaryCountsSubtractDependentCountsWorklet(vtkm::Id firstSupernode,
vtkm::Id firstHypernode)
: FirstSupernode(firstSupernode)
, FirstHypernode(firstHypernode)
{
}
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)
{
// A. Retrieve hyperparent & convert to supernode ID
vtkm::Id hyperparent = hyperparentsPortal.Get(supernode);
vtkm::Id hyperparentSuperId = hypernodesPortal.Get(hyperparent);
// B. If hyperparent is first in sequence, count is already correct
if (hyperparent == this->FirstHypernode)
{
return;
}
// C. Otherwise, subtract out the immediately previous count to get correct value
vtkm::Id supernodeOffset = supernode - this->FirstSupernode;
newSuperArcDependentBoundaryCountPortal.Set(
supernodeOffset,
newSuperArcDependentBoundaryCountPortal.Get(supernodeOffset) -
superarcDependentBoundaryCountPortal.Get(hyperparentSuperId - 1));
// In serial this worklet implements the following operation
/*
for (vtkm::Id supernode = lastSupernode-1; supernode > firstSupernode; supernode--)
// NB: Loops backward to use the correct values, also tests > firstSupernode (the first one is guaranteed to be correct already - see ComputeWeights())
{ // iv. per supernode
// A. Retrieve hyperparent & convert to supernode ID
vtkm::Id hyperparent = contourTree->hyperparents[supernode];
vtkm::Id hyperparentSuperID = contourTree->hypernodes[hyperparent];
// B. If hyperparent is first in sequence, count is already correct
if (hyperparent == firstHypernode)
continue;
// C. Otherwise, subtract out the immediately previous count to get correct value
vtkm::Id supernodeOffset = supernode - firstSupernode;
newSuperArcDependentBoundaryCount[supernodeOffset] -= superarcDependentBoundaryCount[hyperparentSuperID-1];
} // iv. per supernode
*/
}
private:
vtkm::Id FirstSupernode;
vtkm::Id FirstHypernode;
}; // PropagateBoundaryCountsSubtractDependentCountsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,175 @@
//============================================================================
// 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_propagate_boundary_counts_transfer_cumulative_counts_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_propagate_boundary_counts_transfer_cumulative_counts_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 cumulative counts for hyperarcs
/// Part of the BoundaryRestrictedAugmentedContourTree.PropagateBoundaryCounts function
///
/// 4. The partial sum is now over ALL hypertargets, so within each group we need to subtract the first from the last
/// To do so, the last hyperarc in each cluster copies its cumulative count to the output array
class PropagateBoundaryCountsTransferCumulativeCountsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
WholeArrayIn hyperarcTargetSortPermutation, // (input)
WholeArrayIn hyperarcs, // (input) contour tree hyperarcs
WholeArrayIn accumulatedBoundaryCountPortal, // (input)
WholeArrayInOut supernodeTransferBoundaryCountPortal // (input/output)
);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
PropagateBoundaryCountsTransferCumulativeCountsWorklet() {}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hyperarc,
const InFieldPortalType& hyperarcTargetSortPermutationPortal,
const InFieldPortalType& hyperarcsPortal,
const InFieldPortalType& accumulatedBoundaryCountPortal,
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal)
{
// per hyperarc
// retrieve the hypertarget
vtkm::Id hyperarcTarget =
hyperarcsPortal.Get(hyperarcTargetSortPermutationPortal.Get(hyperarc));
// in the last loop, no transfer is needed
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hyperarcTarget))
{
return;
}
// now mask out the flag
hyperarcTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(hyperarcTarget);
// the last one of all has a different rule
if (hyperarc == hyperarcTargetSortPermutationPortal.GetNumberOfValues() - 1)
{ // last hyperarc
supernodeTransferBoundaryCountPortal.Set(
hyperarcTarget,
supernodeTransferBoundaryCountPortal.Get(hyperarcTarget) +
accumulatedBoundaryCountPortal.Get(hyperarc));
} // last hyperarc
// the others compute a delta
else
{ // not last hyperarc
vtkm::Id nextHyperarcTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(
hyperarcsPortal.Get(hyperarcTargetSortPermutationPortal.Get(hyperarc + 1)));
// only write for the last one in the cluster
// note that this is an addition because a target may accumulate in multiple passes
if (hyperarcTarget != nextHyperarcTarget)
{ // no match
supernodeTransferBoundaryCountPortal.Set(
hyperarcTarget,
supernodeTransferBoundaryCountPortal.Get(hyperarcTarget) +
accumulatedBoundaryCountPortal.Get(hyperarc));
} // no match
} // not last hyperarc
// In serial this worklet implements the following operation
/*
for (vtkm::Id hyperarc = 0; hyperarc < hyperarcTargetSortPermutation.size(); hyperarc++)
{ // per hyperarc
// retrieve the hypertarget
vtkm::Id hyperarcTarget = contourTree->hyperarcs[hyperarcTargetSortPermutation[hyperarc]];
// in the last loop, no transfer is needed
if (noSuchElement(hyperarcTarget))
continue;
// now mask out the flag
hyperarcTarget = maskedIndex(hyperarcTarget);
// the last one of all has a different rule
if (hyperarc == hyperarcTargetSortPermutation.size() - 1)
{ // last hyperarc
supernodeTransferBoundaryCount[hyperarcTarget] += accumulatedBoundaryCount[hyperarc];
} // last hyperarc
// the others compute a delta
else
{ // not last hyperarc
vtkm::Id nextHyperarcTarget = maskedIndex(contourTree->hyperarcs[hyperarcTargetSortPermutation[hyperarc+1]]);
// only write for the last one in the cluster
// note that this is an addition because a target may accumulate in multiple passes
if (hyperarcTarget != nextHyperarcTarget)
{ // no match
supernodeTransferBoundaryCount[hyperarcTarget] += accumulatedBoundaryCount[hyperarc];
} // no match
} // not last hyperarc
} // per hyperarc
*/
}
}; // PropagateBoundaryCountsTransferCumulativeCountsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,144 @@
//============================================================================
// 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_propagate_boundary_counts_transfer_dependent_counts_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_propagate_boundary_counts_transfer_dependent_counts_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 PropagateBoundaryCountsTransferDependentCountsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn supernodeIndex, // (input) index of supernodes for iteration
WholeArrayIn hypernodes, // (input) contour tree hypernodes
WholeArrayIn superarcDependentBoundaryCount, // (input)
WholeArrayOut hyperarcDependentBoundaryCount // (output)
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
PropagateBoundaryCountsTransferDependentCountsWorklet(vtkm::Id numSupernodes,
vtkm::Id numHypernodes)
: NumSupernodes(numSupernodes)
, NumHypernodes(numHypernodes)
{
}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& hypernode,
const InFieldPortalType& hypernodesPortal,
const InFieldPortalType& superarcDependentBoundaryCountPortal,
const OutFieldPortalType& hyperarcDependentBoundaryCountPortal)
{
// v. per hypernode
// A.Transfer dependent count from last superarc to hyperarc
// Last superarc for the hyperarc
vtkm::Id lastSuperarc;
// special case for the last hyperarc
if (hypernode == this->NumHypernodes - 1)
{
lastSuperarc = this->NumSupernodes - 1;
}
else
{
lastSuperarc =
vtkm::worklet::contourtree_augmented::MaskedIndex(hypernodesPortal.Get(hypernode + 1)) - 1;
}
// Transfer the dependent count
hyperarcDependentBoundaryCountPortal.Set(
hypernode, superarcDependentBoundaryCountPortal.Get(lastSuperarc));
// In serial this worklet implements the following operation
/*
for (vtkm::Id hypernode = firstHypernode; hypernode < lastHypernode; hypernode++)
{ // v. per hypernode
// A. Transfer dependent count from last superarc to hyperarc
// Last superarc for the hyperarc
vtkm::Id lastSuperarc;
// special case for the last hyperarc
if (hypernode == contourTree->hypernodes.size() - 1)
lastSuperarc = contourTree->supernodes.size() - 1;
else
lastSuperarc = maskedIndex(contourTree->hypernodes[hypernode + 1]) - 1;
// Transfer the dependent count
hyperarcDependentBoundaryCount[hypernode] = superarcDependentBoundaryCount[lastSuperarc];
*/
}
private:
vtkm::Id NumSupernodes;
vtkm::Id NumHypernodes;
}; // PropagateBoundaryCountsTransferDependentCountsWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,99 @@
//============================================================================
// 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_select_range_functor_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_select_range_functor_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace bract_maker
{
//Simple functor to subset a VTKm ArrayHandle
class SelectRangeFunctor
{
public:
VTKM_EXEC_CONT
SelectRangeFunctor();
VTKM_EXEC_CONT
SelectRangeFunctor(const vtkm::worklet::contourtree_augmented::IdArrayType& dataArray,
vtkm::Id startIndex)
: DataArray(dataArray)
, StartIndex(startIndex)
{
}
VTKM_EXEC_CONT
vtkm::Id operator()(const vtkm::Id index) const
{
return this->DataArray.ReadPortal().Get(this->StartIndex + index);
}
private:
vtkm::worklet::contourtree_augmented::IdArrayType DataArray;
vtkm::Id StartIndex;
};
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,152 @@
//============================================================================
// 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_up_and_down_neighbours_worklet_h
#define vtk_m_worklet_contourtree_distributed_bract_maker_set_up_and_down_neighbours_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 SetUpAndDownNeighboursWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn bractVertexSuperset, // input
FieldIn bractSuperarcs, // input
WholeArrayIn meshSortIndex, // input
WholeArrayOut upNeighbour, // output
WholeArrayOut downNeighbour // output
);
using ExecutionSignature = void(InputIndex, _2, _1, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
SetUpAndDownNeighboursWorklet() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& from,
vtkm::Id& to,
InFieldPortalType bractVertexSupersetPortal,
InFieldPortalType meshSortIndexPortal,
OutFieldPortalType upNeighbourPortal,
OutFieldPortalType downNeighbourPortal)
{
// per vertex
// ignore the last terminating edge
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
{
return;
}
// now find the sort index of the from and to
vtkm::Id fromSort = meshSortIndexPortal.Get(bractVertexSupersetPortal.Get(from));
vtkm::Id toSort = meshSortIndexPortal.Get(bractVertexSupersetPortal.Get(to));
// use this to identify direction of edge
if (fromSort < toSort)
{ // from is lower
upNeighbourPortal.Set(from, to);
downNeighbourPortal.Set(to, from);
} // from is lower
else
{ // to is lower
upNeighbourPortal.Set(to, from);
downNeighbourPortal.Set(from, to);
} // to is lower
// In serial this worklet implements the following operation
/*
// a. Loop through all of the superarcs in the return tree, retrieving the two ends
for (indexType from = 0; from < bractVertexSuperset.size(); from++)
{ // per vertex
indexType to = bract->superarcs[from];
// ignore the last terminating edge
if (noSuchElement(to))
continue;
// now find the sort index of the from and to
indexType fromSort = mesh->SortIndex(bractVertexSuperset[from]);
indexType toSort = mesh->SortIndex(bractVertexSuperset[to]);
// use this to identify direction of edge
if (fromSort < toSort)
{ // from is lower
upNeighbour[from] = to;
downNeighbour[to] = from;
} // from is lower
else
{ // to is lower
upNeighbour[to] = from;
downNeighbour[from] = to;
} // to is lower
} // per vertex
*/
}
}; // SetUpAndDownNeighboursWorklet
} // namespace bract_maker
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif