First implementation of contour tree 2D and 3D, serial and cuda.

This commit is contained in:
Patricia Kroll Fasel - 090207 2017-01-09 13:54:47 -07:00
parent 589285eb5e
commit 9412584bf2
61 changed files with 8656 additions and 0 deletions

@ -24,6 +24,7 @@
set(CMAKE_PREFIX_PATH ${VTKm_BINARY_DIR}/${VTKm_INSTALL_CONFIG_DIR})
add_subdirectory(clipping)
add_subdirectory(contour_tree)
add_subdirectory(demo)
add_subdirectory(dynamic_dispatcher)
add_subdirectory(hello_world)

@ -0,0 +1,75 @@
##=============================================================================
##
## 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 2015 Sandia Corporation.
## Copyright 2015 UT-Battelle, LLC.
## Copyright 2015 Los Alamos National Security.
##
## Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
## 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.
##
##=============================================================================
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET
OPTIONAL_COMPONENTS Serial CUDA TBB OpenGL
)
add_executable(ContourTreeMesh2D_SERIAL ContourTreeMesh2D.cxx)
target_include_directories(ContourTreeMesh2D_SERIAL PRIVATE ${GLUT_INCLUDE_DIR} ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh2D_SERIAL ${GLUT_LIBRARIES} ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh2D_SERIAL PRIVATE ${VTKm_COMPILE_OPTIONS})
add_executable(ContourTreeMesh3D_SERIAL ContourTreeMesh3D.cxx)
target_include_directories(ContourTreeMesh3D_SERIAL PRIVATE ${GLUT_INCLUDE_DIR} ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh3D_SERIAL ${GLUT_LIBRARIES} ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh3D_SERIAL PRIVATE ${VTKm_COMPILE_OPTIONS})
if(VTKm_CUDA_FOUND)
set(old_nvcc_flags ${CUDA_NVCC_FLAGS})
set(old_cxx_flags ${CMAKE_CXX_FLAGS})
vtkm_setup_nvcc_flags( old_nvcc_flags old_cxx_flags)
vtkm_disable_troublesome_thrust_warnings()
# Cuda compiles do not respect target_include_directories
cuda_include_directories(${VTKm_INCLUDE_DIRS})
set (cudaSource "${CMAKE_CURRENT_BINARY_DIR}/ContourTreeMesh2D.cu")
configure_file(ContourTreeMesh2D.cxx ${cudaSource} COPYONLY)
cuda_add_executable(ContourTreeMesh2D_CUDA ${cudaSource})
target_include_directories(ContourTreeMesh2D_CUDA PRIVATE ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh2D_CUDA ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh2D_CUDA PRIVATE ${VTKm_COMPILE_OPTIONS})
set (cudaSource "${CMAKE_CURRENT_BINARY_DIR}/ContourTreeMesh3D.cu")
configure_file(ContourTreeMesh3D.cxx ${cudaSource} COPYONLY)
cuda_add_executable(ContourTreeMesh3D_CUDA ${cudaSource})
target_include_directories(ContourTreeMesh3D_CUDA PRIVATE ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh3D_CUDA ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh3D_CUDA PRIVATE ${VTKm_COMPILE_OPTIONS})
set(CUDA_NVCC_FLAGS ${old_nvcc_flags})
set(CMAKE_CXX_FLAGS ${old_cxx_flags})
endif()
if(VTKm_TBB_FOUND)
add_executable(ContourTreeMesh2D_TBB ContourTreeMesh2DTBB.cxx)
target_include_directories(ContourTreeMesh2D_TBB PRIVATE ${GLUT_INCLUDE_DIR} ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh2D_TBB ${GLUT_LIBRARIES} ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh2D_TBB PRIVATE ${VTKm_COMPILE_OPTIONS})
add_executable(ContourTreeMesh3D_TBB ContourTreeMesh3DTBB.cxx)
target_include_directories(ContourTreeMesh3D_TBB PRIVATE ${GLUT_INCLUDE_DIR} ${VTKm_INCLUDE_DIRS})
target_link_libraries(ContourTreeMesh3D_TBB ${GLUT_LIBRARIES} ${VTKm_LIBRARIES})
target_compile_options(ContourTreeMesh3D_TBB PRIVATE ${VTKm_COMPILE_OPTIONS})
endif()

@ -0,0 +1,84 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//We first check if VTKM_DEVICE_ADAPTER is defined, so that when TBB and CUDA
//includes this file we use the device adapter that they have set.
#ifndef VTKM_DEVICE_ADAPTER
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_SERIAL
#endif
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/filter/ContourTreeUniform.h>
// Compute and render an isosurface for a uniform grid example
int main(int argc, char* argv[])
{
std::cout << "ContourTreeMesh2D Example" << std::endl;
if (argc != 2) {
std::cout << "Parameter is fileName" << std::endl;
std::cout << "File is expected to be ASCII with xdim ydim integers " << std::endl;
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
return 0;
}
// open input file
ifstream inFile(argv[1]);
if (inFile.bad()) return 0;
// read size of mesh
vtkm::Id2 vdims;
inFile >> vdims[0];
inFile >> vdims[1];
vtkm::Id nVertices = vdims[0] * vdims[1];
// read data
vtkm::Float32 values[nVertices];
for (int vertex = 0; vertex < nVertices; vertex++)
inFile >> values[vertex];
inFile.close();
// build the input dataset
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::cont::DataSet inDataSet = dsb.Create(vdims);
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(inDataSet, "values", values, nVertices);
// Output data set is pairs of saddle and peak vertex IDs
vtkm::filter::ResultField result;
// Convert 2D mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeMesh2D filter;
result = filter.Execute(inDataSet, std::string("values"));
vtkm::cont::Field resultField = result.GetField();
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
resultField.GetData().CopyTo(saddlePeak);
return 0;
}
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
# pragma GCC diagnostic pop
#endif

@ -0,0 +1,85 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//We first check if VTKM_DEVICE_ADAPTER is defined, so that when TBB and CUDA
//includes this file we use the device adapter that they have set.
#ifndef VTKM_DEVICE_ADAPTER
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_SERIAL
#endif
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/filter/ContourTreeUniform.h>
// Compute and render an isosurface for a uniform grid example
int main(int argc, char* argv[])
{
std::cout << "ContourTreeMesh3D Example" << std::endl;
if (argc != 2) {
std::cout << "Parameter is fileName" << std::endl;
std::cout << "File is expected to be ASCII with xdim ydim zdim integers " << std::endl;
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
return 0;
}
// open input file
ifstream inFile(argv[1]);
if (inFile.bad()) return 0;
// read size of mesh
vtkm::Id3 vdims;
inFile >> vdims[0];
inFile >> vdims[1];
inFile >> vdims[2];
vtkm::Id nVertices = vdims[0] * vdims[1] * vdims[2];
// read data
vtkm::Float32 values[nVertices];
for (int vertex = 0; vertex < nVertices; vertex++)
inFile >> values[vertex];
inFile.close();
// build the input dataset
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::cont::DataSet inDataSet = dsb.Create(vdims);
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(inDataSet, "values", values, nVertices);
// Output data set is pairs of saddle and peak vertex IDs
vtkm::filter::ResultField result;
// Convert 3D mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeMesh3D filter;
result = filter.Execute(inDataSet, std::string("values"));
vtkm::cont::Field resultField = result.GetField();
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
resultField.GetData().CopyTo(saddlePeak);
return 0;
}
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
# pragma GCC diagnostic pop
#endif

@ -22,6 +22,7 @@ set(headers
CellAverage.h
CleanGrid.h
Clip.h
ContourTreeUniform.h
ExternalFaces.h
FieldMetadata.h
FilterCell.h
@ -47,6 +48,7 @@ set(header_template_sources
CellAverage.hxx
CleanGrid.hxx
Clip.hxx
ContourTreeUniform.hxx
ExternalFaces.hxx
FilterCell.hxx
FilterDataSet.hxx

@ -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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtk_m_filter_ContourTreeUniform_h
#define vtk_m_filter_ContourTreeUniform_h
#include <vtkm/filter/FilterField.h>
namespace vtkm {
namespace filter {
class ContourTreeMesh2D : public vtkm::filter::FilterField<ContourTreeMesh2D>
{
public:
VTKM_CONT
ContourTreeMesh2D();
template<typename T, typename StorageType, typename DerivedPolicy, typename DeviceAdapter>
VTKM_CONT
vtkm::filter::ResultField DoExecute(const vtkm::cont::DataSet &input,
const vtkm::cont::ArrayHandle<T, StorageType> &field,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy,
const DeviceAdapter& tag);
};
template<>
class FilterTraits<ContourTreeMesh2D>
{
public:
typedef TypeListTagScalarAll InputFieldTypeList;
};
class ContourTreeMesh3D : public vtkm::filter::FilterField<ContourTreeMesh3D>
{
public:
VTKM_CONT
ContourTreeMesh3D();
template<typename T, typename StorageType, typename DerivedPolicy, typename DeviceAdapter>
VTKM_CONT
vtkm::filter::ResultField DoExecute(const vtkm::cont::DataSet &input,
const vtkm::cont::ArrayHandle<T, StorageType> &field,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy,
const DeviceAdapter& tag);
};
template<>
class FilterTraits<ContourTreeMesh3D>
{
public:
typedef TypeListTagScalarAll InputFieldTypeList;
};
}
} // namespace vtkm::filter
#include <vtkm/filter/ContourTreeUniform.hxx>
#endif // vtk_m_filter_ContourTreeUniform_h

@ -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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#include <vtkm/worklet/ContourTreeUniform.h>
namespace vtkm {
namespace filter {
//-----------------------------------------------------------------------------
ContourTreeMesh2D::ContourTreeMesh2D()
{
this->SetOutputFieldName("saddlePeak");
}
//-----------------------------------------------------------------------------
template<typename T,
typename StorageType,
typename DerivedPolicy,
typename DeviceAdapter>
vtkm::filter::ResultField
ContourTreeMesh2D::DoExecute(const vtkm::cont::DataSet &input,
const vtkm::cont::ArrayHandle<T,StorageType> &field,
const vtkm::filter::FieldMetadata &fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy,
const DeviceAdapter& device)
{
if (fieldMeta.IsPointField() == false) {
std::cout << "ERROR: Point field expected" << std::endl;
return vtkm::filter::ResultField();
}
// Collect sizing information from the dataset
vtkm::cont::CellSetStructured<2> cellSet;
input.GetCellSet(0).CopyTo(cellSet);
// How should policy be used?
vtkm::filter::ApplyPolicy(cellSet, policy);
vtkm::Id2 pointDimensions = cellSet.GetPointDimensions();
vtkm::Id nRows = pointDimensions[0];
vtkm::Id nCols = pointDimensions[1];
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
vtkm::worklet::ContourTreeMesh2D worklet;
worklet.Run(field, nRows, nCols, saddlePeak, device);
return vtkm::filter::ResultField(input,
saddlePeak,
this->GetOutputFieldName(),
fieldMeta.GetAssociation(),
fieldMeta.GetCellSetName());
}
//-----------------------------------------------------------------------------
ContourTreeMesh3D::ContourTreeMesh3D()
{
this->SetOutputFieldName("saddlePeak");
}
//-----------------------------------------------------------------------------
template<typename T,
typename StorageType,
typename DerivedPolicy,
typename DeviceAdapter>
vtkm::filter::ResultField
ContourTreeMesh3D::DoExecute(const vtkm::cont::DataSet &input,
const vtkm::cont::ArrayHandle<T,StorageType> &field,
const vtkm::filter::FieldMetadata &fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy,
const DeviceAdapter& device)
{
if (fieldMeta.IsPointField() == false) {
std::cout << "ERROR: Point field expected" << std::endl;
return vtkm::filter::ResultField();
}
// Collect sizing information from the dataset
vtkm::cont::CellSetStructured<3> cellSet;
input.GetCellSet(0).CopyTo(cellSet);
// How should policy be used?
vtkm::filter::ApplyPolicy(cellSet, policy);
vtkm::Id3 pointDimensions = cellSet.GetPointDimensions();
vtkm::Id nRows = pointDimensions[0];
vtkm::Id nCols = pointDimensions[1];
vtkm::Id nSlices = pointDimensions[2];
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
vtkm::worklet::ContourTreeMesh3D worklet;
worklet.Run(field, nRows, nCols, nSlices, saddlePeak, device);
return vtkm::filter::ResultField(input,
saddlePeak,
this->GetOutputFieldName(),
fieldMeta.GetAssociation(),
fieldMeta.GetCellSetName());
}
}
} // namespace vtkm::filter

@ -22,6 +22,7 @@ set(unit_tests
UnitTestCellAverageFilter.cxx
UnitTestCleanGrid.cxx
UnitTestClipFilter.cxx
UnitTestContourTreeUniformFilter.cxx
UnitTestExternalFacesFilter.cxx
UnitTestFieldMetadata.cxx
UnitTestGradient.cxx

@ -0,0 +1,189 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/filter/ContourTreeUniform.h>
#include <vtkm/cont/testing/Testing.h>
namespace {
//
// Test 2D regular dataset
//
vtkm::cont::DataSet MakeContourTreeMesh2DTestDataSet()
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id2 dimensions(5,5);
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::DataSetFieldAdd dsf;
const vtkm::Id nVerts = 25;
vtkm::Float32 var[nVerts] = {
100.0f, 78.0f, 49.0f, 17.0f, 1.0f,
94.0f, 71.0f, 47.0f, 33.0f, 6.0f,
52.0f, 44.0f, 50.0f, 45.0f, 48.0f,
8.0f, 12.0f, 46.0f, 91.0f, 43.0f,
0.0f, 5.0f, 51.0f, 76.0f, 83.0f};
dsf.AddPointField(dataSet, "values", var, nVerts);
return dataSet;
}
//
// Create a uniform 2D structured cell set as input with values for contours
//
void TestContourTree_Mesh2D_DEM_Triangulation()
{
std::cout << "Testing ContourTree_Mesh2D Filter" << std::endl;
typedef VTKM_DEFAULT_DEVICE_ADAPTER_TAG DeviceAdapter;
// Create the input uniform cell set with values to contour
vtkm::cont::DataSet inDataSet = MakeContourTreeMesh2DTestDataSet();
// Output data set is pairs of saddle and peak vertex IDs
vtkm::filter::ResultField result;
// Convert 2D mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeMesh2D contourTreeMesh2D;
result = contourTreeMesh2D.Execute(inDataSet, std::string("values"));
vtkm::cont::Field resultField = result.GetField();
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
resultField.GetData().CopyTo(saddlePeak);
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetNumberOfValues(), 7), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(0), vtkm::make_Pair( 0, 12)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(1), vtkm::make_Pair( 4, 13)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(2), vtkm::make_Pair(12, 13)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(3), vtkm::make_Pair(12, 18)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(4), vtkm::make_Pair(12, 20)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(5), vtkm::make_Pair(13, 14)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(6), vtkm::make_Pair(13, 19)), "Wrong result for ContourTree filter");
}
//
// Test 3D regular dataset
//
vtkm::cont::DataSet MakeContourTreeMesh3DTestDataSet()
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id3 dimensions(5,5,5);
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::DataSetFieldAdd dsf;
const vtkm::Id nVerts = 125;
vtkm::Float32 var[nVerts] = {
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 99.0f, 90.0f, 85.0f, 0.0f,
0.0f, 95.0f, 80.0f, 95.0f, 0.0f,
0.0f, 85.0f, 90.0f, 99.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 75.0f, 50.0f, 65.0f, 0.0f,
0.0f, 55.0f, 15.0f, 45.0f, 0.0f,
0.0f, 60.0f, 40.0f, 70.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 97.0f, 87.0f, 82.0f, 0.0f,
0.0f, 92.0f, 77.0f, 92.0f, 0.0f,
0.0f, 82.0f, 87.0f, 97.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
dsf.AddPointField(dataSet, "values", var, nVerts);
return dataSet;
}
//
// Create a uniform 3D structured cell set as input with values for contours
//
void TestContourTree_Mesh3D_DEM_Triangulation()
{
std::cout << "Testing ContourTree_Mesh3D Filter" << std::endl;
// Create the input uniform cell set with values to contour
vtkm::cont::DataSet dataSet = MakeContourTreeMesh3DTestDataSet();
vtkm::cont::CellSetStructured<3> cellSet;
dataSet.GetCellSet().CopyTo(cellSet);
vtkm::Id3 pointDimensions = cellSet.GetPointDimensions();
vtkm::Id nRows = pointDimensions[0];
vtkm::Id nCols = pointDimensions[1];
vtkm::Id nSlices = pointDimensions[2];
vtkm::cont::ArrayHandle<vtkm::Float32> fieldArray;
dataSet.GetField("values").GetData().CopyTo(fieldArray);
// Output saddle peak pairs array
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
// Create the worklet and run it
vtkm::worklet::ContourTreeMesh3D contourTreeMesh3D;
contourTreeMesh3D.Run(fieldArray,
nRows,
nCols,
nSlices,
saddlePeak,
DeviceAdapter());
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetNumberOfValues(), 9), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(0), vtkm::make_Pair( 0, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(1), vtkm::make_Pair(31, 42)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(2), vtkm::make_Pair(42, 43)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(3), vtkm::make_Pair(42, 56)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(4), vtkm::make_Pair(56, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(5), vtkm::make_Pair(56, 92)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(6), vtkm::make_Pair(62, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(7), vtkm::make_Pair(81, 92)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(8), vtkm::make_Pair(92, 93)), "Wrong result for ContourTree filter");
}
void TestContourTreeUniform()
{
TestContourTree_Mesh2D_DEM_Triangulation();
TestContourTree_Mesh3D_DEM_Triangulation();
}
}
int UnitTestContourTreeUniformFilter(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestContourTreeUniform);
}

@ -23,6 +23,7 @@ set(headers
CellAverage.h
CellDeepCopy.h
Clip.h
ContourTreeUniform.h
DispatcherMapField.h
DispatcherMapTopology.h
DispatcherStreamingMapField.h
@ -54,6 +55,7 @@ set(headers
#-----------------------------------------------------------------------------
add_subdirectory(internal)
add_subdirectory(contourtree)
add_subdirectory(splatkernels)
add_subdirectory(wavelets)

@ -0,0 +1,164 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtk_m_worklet_ContourTreeUniform_h
#define vtk_m_worklet_ContourTreeUniform_h
#include <vtkm/Math.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Field.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_Triangulation.h>
#include <vtkm/worklet/contourtree/MergeTree.h>
#include <vtkm/worklet/contourtree/ChainGraph.h>
#include <vtkm/worklet/contourtree/ContourTree.h>
#ifndef VTKM_DEVICE_ADAPTER
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_SERIAL
#endif
const bool JOIN = true;
const bool SPLIT = false;
const bool JOIN_3D = true;
const bool SPLIT_3D = false;
typedef VTKM_DEFAULT_DEVICE_ADAPTER_TAG DeviceAdapter;
namespace vtkm {
namespace worklet {
class ContourTreeMesh2D
{
public:
template<typename FieldType, typename StorageType, typename DeviceAdapter>
void Run(vtkm::cont::ArrayHandle<FieldType, StorageType> fieldArray,
vtkm::Id nRows,
vtkm::Id nCols,
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > &saddlePeak,
DeviceAdapter device)
{
vtkm::Id nSlices = 1;
// Build the mesh and fill in the values
contourtree::Mesh2D_DEM_Triangulation<FieldType,StorageType,DeviceAdapter>
mesh(fieldArray, device, nRows, nCols);
// Initialize the join tree so that all arcs point to maxima
contourtree::MergeTree<FieldType,StorageType,DeviceAdapter>
joinTree(fieldArray, device, nRows, nCols, nSlices, JOIN);
mesh.SetStarts(joinTree.extrema, JOIN);
joinTree.BuildRegularChains();
// Create the active topology graph from the regular graph
contourtree::ChainGraph<FieldType,StorageType,DeviceAdapter>
joinGraph(fieldArray, device, joinTree.extrema, JOIN);
mesh.SetSaddleStarts(joinGraph, JOIN);
// Call join graph to finish computation
joinGraph.Compute(joinTree.saddles);
// Initialize the split tree so that all arcs point to maxima
contourtree::MergeTree<FieldType,StorageType,DeviceAdapter>
splitTree(fieldArray, device, nRows, nCols, nSlices, SPLIT);
mesh.SetStarts(splitTree.extrema, SPLIT);
splitTree.BuildRegularChains();
// Create the active topology graph from the regular graph
contourtree::ChainGraph<FieldType,StorageType,DeviceAdapter>
splitGraph(fieldArray, device, splitTree.extrema, SPLIT);
mesh.SetSaddleStarts(splitGraph, SPLIT);
// Call split graph to finish computation
splitGraph.Compute(splitTree.saddles);
// Now compute the contour tree
contourtree::ContourTree<FieldType,StorageType,DeviceAdapter>
contourTree(fieldArray, device,
joinTree, joinGraph,
splitTree, splitGraph);
contourTree.CollectSaddlePeak(saddlePeak);
}
};
class ContourTreeMesh3D
{
public:
template<typename FieldType, typename StorageType, typename DeviceAdapter>
void Run(vtkm::cont::ArrayHandle<FieldType, StorageType> fieldArray,
vtkm::Id nRows,
vtkm::Id nCols,
vtkm::Id nSlices,
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > &saddlePeak,
DeviceAdapter device)
{
// Build the mesh and fill in the values
contourtree::Mesh3D_DEM_Triangulation<FieldType,StorageType,DeviceAdapter>
mesh(fieldArray, device, nRows, nCols, nSlices);
// Initialize the join tree so that all arcs point to maxima
contourtree::MergeTree<FieldType,StorageType,DeviceAdapter>
joinTree(fieldArray, device, nRows, nCols, nSlices, JOIN_3D);
mesh.SetStarts(joinTree.extrema, JOIN_3D);
joinTree.BuildRegularChains();
// Create the active topology graph from the regular graph
contourtree::ChainGraph<FieldType,StorageType,DeviceAdapter>
joinGraph(fieldArray, device, joinTree.extrema, JOIN_3D);
mesh.SetSaddleStarts(joinGraph, JOIN_3D);
// Call join graph to finish computation
joinGraph.Compute(joinTree.saddles);
// Initialize the split tree so that all arcs point to maxima
contourtree::MergeTree<FieldType,StorageType,DeviceAdapter>
splitTree(fieldArray, device, nRows, nCols, nSlices, SPLIT_3D);
mesh.SetStarts(splitTree.extrema, SPLIT_3D);
splitTree.BuildRegularChains();
// Create the active topology graph from the regular graph
contourtree::ChainGraph<FieldType,StorageType,DeviceAdapter>
splitGraph(fieldArray, device, splitTree.extrema, SPLIT_3D);
mesh.SetSaddleStarts(splitGraph, SPLIT_3D);
// Call split graph to finish computation
splitGraph.Compute(splitTree.saddles);
// Now compute the contour tree
contourtree::ContourTree<FieldType,StorageType,DeviceAdapter>
contourTree(fieldArray, device,
joinTree, joinGraph,
splitTree, splitGraph);
contourTree.CollectSaddlePeak(saddlePeak);
}
};
}
} // namespace vtkm::worklet
#endif // vtk_m_worklet_ContourTreeUniform_h

@ -0,0 +1,147 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// ActiveEdgeTransferrer.h - functor that sets new active edges per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor identifies for each vertex which edges to keep. For arbitrary meshes,
// this should use reductions. For regular meshes, this way is faster due to low bounded
// updegree.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtk_m_worklet_contourtree_active_edge_transferrer_h
#define vtk_m_worklet_contourtree_active_edge_transferrer_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet: set initial chain maximum value
template <typename DeviceAdapter>
class ActiveEdgeTransferrer : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) active vertex ID
FieldIn<IdType> newPosition, // (input) new position of edge in array
FieldIn<IdType> newOutdegree, // (input) the new updegree computed
WholeArrayInOut<IdType> firstEdge, // (i/o) first edge of each active vertex
WholeArrayInOut<IdType> outdegree, // (i/o) existing vertex updegrees
WholeArrayInOut<IdType> chainExtremum, // (i/o) chain extremum for vertices
WholeArrayInOut<IdType> edgeFar, // (i/o) high end of each edge
WholeArrayOut<IdType> newActiveEdges); // (output) new active edge list
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8);
typedef _1 InputDomain;
// Passed in constructor because of argument limit on operator
typedef typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
IdPortalType activeEdges; // (input) active edges
IdPortalType prunesTo; // (input) where a vertex prunes to
// Constructor
VTKM_EXEC_CONT
ActiveEdgeTransferrer(IdPortalType ActiveEdges,
IdPortalType PrunesTo) :
activeEdges(ActiveEdges),
prunesTo(PrunesTo) {}
// WARNING: POTENTIAL RISK FOR I/O
// chainMaximum is safe for I/O here because:
// we have previously eliminated maxima from the active vertex list
// we lookup chainMaximum of edgeHigh, which is guaranteed to be a maximum
// therefore, the chainMaximum entries edited are *NEVER* also accessed & v.v.
// edgeHigh is safe to edit, because each element only accesses it's own, and
// reads the current value before writing to it
// the same is true of firstEdge and updegree
template <typename InOutFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id &vertexID,
const vtkm::Id &newPosition,
const vtkm::Id &newOutdegree,
const InOutFieldPortalType &firstEdge,
const InOutFieldPortalType &outdegree,
const InOutFieldPortalType &chainExtremum,
const InOutFieldPortalType &edgeFar,
const OutFieldPortalType &newActiveEdges) const
{
// retrieve actual vertex ID & first edge
vtkm::Id edgeFirst = firstEdge.Get(vertexID);
// internal counter for # of edges
vtkm::Id whichEdge = newPosition;
// walk through the vertex edges, counting as we go
for (vtkm::Id edge = 0; edge < outdegree.Get(vertexID); edge++)
{
// compute the index and edge ID of this edge
vtkm::Id edgeIndex = edgeFirst + edge;
vtkm::Id edgeID = activeEdges.Get(edgeIndex);
// retrieve the vertex ID for the high end & update for pruning
vtkm::Id highEnd = prunesTo.Get(chainExtremum.Get(edgeFar.Get(edgeID)));
// we want to ignore edges that lead back to this vertex
if (highEnd != vertexID)
{
// reset the high end of the edge, copying downwards
edgeFar.Set(edgeID, highEnd);
// and keep the edge around
newActiveEdges.Set(whichEdge++, edgeID);
// and reset the chain maximum for good measure
chainExtremum.Set(vertexID, highEnd);
}
}
// now reset the firstEdge variable for this vertex
outdegree.Set(vertexID, newOutdegree);
firstEdge.Set(vertexID, newPosition);
}
}; // ActiveEdgeTransferrer
}
}
}
#endif

@ -0,0 +1,28 @@
##============================================================================
## 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 2016 Sandia Corporation.
## Copyright 2016 UT-Battelle, LLC.
## Copyright 2016 Los Alamos National Security.
##
## Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
## 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.
##============================================================================
set(headers
# Mesh2D_DEM_VertexOutdegreeStarter.h
Mesh2D_DEM_VertexStarter.h
# ActiveEdgeTransferrer.h
)
#-----------------------------------------------------------------------------
vtkm_declare_headers(${headers})

@ -0,0 +1,89 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// ChainDoubler.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
// This functor implements chain-doubling (pointer-doubling), but minimises memory writeback
// by testing whether we've hit the end of the chain already
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_chain_doubler_h
#define vtkm_worklet_contourtree_chain_doubler_h
namespace vtkm {
namespace worklet {
namespace contourtree {
// Functor for doing chain doubling
// Unary because it takes the index of the element to process, and is not guaranteed to
// write back
// moreover, we aren't worried about out-of-sequence writes, since the worst that happens
// is that an element gets pointer-tripled in the iteration. It will still converge to the
// same destination.
class ChainDoubler : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID,
WholeArrayInOut<IdType> chains);
typedef void ExecutionSignature(_1, _2);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
ChainDoubler() {}
template <typename InOutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertexID,
const InOutFieldPortalType& chains) const
{
vtkm::Id next = chains.Get(vertexID);
vtkm::Id doubleNext = chains.Get(next);
if (next != doubleNext)
chains.Set(vertexID, doubleNext);
}
}; // ChainDoubler
}
}
}
#endif

@ -0,0 +1,732 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// ChainGraph.h - class representing the active graph being modified
//
//=======================================================================================
//
// COMMENTS:
//
// The old ChainGraph has been abstracted a little further - it still does the same job
// of carrying most of the intermediate stages. However, since the chain building is
// also needed by the mesh to set up the initial graph input, it has been moved (for now
// to Types.h)
//
// There will be no explicit constructor - instead, it's the mesh's job to initialise
// a valid object of this type
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_chaingraph_h
#define vtkm_worklet_contourtree_chaingraph_h
#include <vtkm/worklet/contourtree/PrintVectors.h>
#include <vtkm/worklet/contourtree/EdgePeakComparator.h>
#include <vtkm/worklet/contourtree/GoverningSaddleFinder.h>
#include <vtkm/worklet/contourtree/RegularPointTransferrer.h>
#include <vtkm/worklet/contourtree/VertexDegreeUpdater.h>
#include <vtkm/worklet/contourtree/ActiveEdgeTransferrer.h>
#include <vtkm/worklet/contourtree/ChainDoubler.h>
#include <vtkm/worklet/contourtree/SaddleAscentFunctor.h>
#include <vtkm/worklet/contourtree/SaddleAscentTransferrer.h>
#include <vtkm/worklet/contourtree/TrunkBuilder.h>
#include <vtkm/worklet/contourtree/JoinTreeTransferrer.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#define DEBUG_PRINT 1
//#define DEBUG_FUNCTION_ENTRY 1
//#define DEBUG_TIMING 1
namespace vtkm {
namespace worklet {
namespace contourtree {
#define DEBUG_STRING_TRANSFER_GOVERNING_SADDLES "Extrema should now be assigned"
#define DEBUG_STRING_TRANSFER_SADDLE_STARTS "Transfer Saddle Starts "
#define DEBUG_STRING_TRANSFERRED_SADDLE_STARTS "Saddle Starts Transferred"
#define DEBUG_STRING_TRANSFER_TO_MERGE_TREE "Transfer to Merge Tree"
#define DEBUG_STRING_OUTDEGREE "Outdegree"
#define DEBUG_STRING_CHAINEXT "Chain Ext"
#define DEBUG_STRING_ACTIVE_OUTDEGREE "Active Outdegree"
#define DEBUG_STRING_ACTIVE_CHAINEXT "Active Chain Ext"
#define DEBUG_STRING_FAR_ID "Far"
#define DEBUG_STRING_FAR_INDEX "Far Index"
#define DEBUG_STRING_FAR_VALUE "Far Value"
#define DEBUG_STRING_NEAR_ID "Near"
#define DEBUG_STRING_NEAR_INDEX "Near Index"
#define DEBUG_STRING_NEAR_VALUE "Near Value"
#define DEBUG_STRING_EDGE_FAR_ID "Edge Far"
#define DEBUG_STRING_EDGE_NEAR_ID "Edge Near"
#define DEBUG_STRING_EDGE_NEAR_INDEX "Edge Near Index"
#define DEBUG_STRING_EDGE_NEAR_VALUE "Edge Near Value"
#define DEBUG_STRING_SORTED_NEAR_ID "Sorted Near"
#define DEBUG_STRING_SORTED_NEAR_INDEX "Sorted Near Index"
#define DEBUG_STRING_SORTED_NEAR_VALUE "Sorted Near Value"
#define DEBUG_STRING_SORTED_FAR_ID "Sorted Far"
template <typename T, typename StorageType, typename DeviceAdapter>
class ChainGraph
{
public:
typedef typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter> DeviceAlgorithm;
// we will want a reference to the original data array
const vtkm::cont::ArrayHandle<T,StorageType> &values;
// device
DeviceAdapter device;
// we will also want a reference to the arc array where we write the output
vtkm::cont::ArrayHandle<vtkm::Id> &arcArray;
// for each vertex, we need to know where it is in the original data array
vtkm::cont::ArrayHandle<vtkm::Id> valueIndex;
// and we also need the orientation of the edges (i.e. is it join or split)
bool isJoinGraph;
// and we will store the number of iterations the computation took here
vtkm::Id nIterations;
// array recording pruning sequence
// pseudo-extrema prune to pseudo-saddles
// all others prune to pseudo-extrema
vtkm::cont::ArrayHandle<vtkm::Id> prunesTo;
// we also want to keep track of the first edge for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> firstEdge;
// and the outdegree for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> outdegree;
// finally, we need to keep track of the chain extremum for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> chainExtremum;
// we will also need to keep track of both near and far ends of each edge
vtkm::cont::ArrayHandle<vtkm::Id> edgeFar;
vtkm::cont::ArrayHandle<vtkm::Id> edgeNear;
// we will also keep track of the currently active set of vertices and edges
vtkm::cont::ArrayHandle<vtkm::Id> activeVertices;
vtkm::cont::ArrayHandle<vtkm::Id> activeEdges;
// and an array for sorting edges
vtkm::cont::ArrayHandle<vtkm::Id> edgeSorter;
// constructor takes necessary references
ChainGraph(const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::cont::ArrayHandle<vtkm::Id> &ArcArray,
bool IsJoinGraph) :
values(Values),
device(Device),
arcArray(ArcArray),
isJoinGraph(IsJoinGraph) {}
// sets initial size of vertex arrays
void AllocateVertexArrays(vtkm::Id Size);
// sets initial size of edge arrays
void AllocateEdgeArrays(vtkm::Id Size);
// routine that builds the merge graph once the initial vertices & edges are set
void Compute(vtkm::cont::ArrayHandle<vtkm::Id> &saddles);
// sorts saddle starts to find governing saddles
void FindGoverningSaddles();
// marks now regular points for removal
void TransferRegularPoints();
// compacts the active vertex list
void CompactActiveVertices();
// compacts the active edge list
void CompactActiveEdges();
// builds the chains for the new active vertices
void BuildChains();
// suppresses non-saddles for the governing saddles pass
void TransferSaddleStarts();
// sets all remaining active vertices
void BuildTrunk();
// transfers partial results to merge tree array
void TransferToMergeTree(vtkm::cont::ArrayHandle<vtkm::Id> &saddles);
// prints the contents of the topology graph in a standard format
void DebugPrint(const char *message);
} ; // class ChainGraph
// sets initial size of vertex arrays
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::AllocateVertexArrays(vtkm::Id Size)
{
valueIndex.Allocate(Size);
prunesTo.Allocate(Size);
firstEdge.Allocate(Size);
outdegree.Allocate(Size);
chainExtremum.Allocate(Size);
activeVertices.Allocate(Size);
} // AllocateVertexArrays()
// sets initial size of edge arrays
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::AllocateEdgeArrays(vtkm::Id Size)
{
edgeFar.Allocate(Size);
edgeNear.Allocate(Size);
activeEdges.Allocate(Size);
} // AllocateEdgeArrays()
// routine that builds the merge graph once the initial vertices & edges are set
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::Compute(vtkm::cont::ArrayHandle<vtkm::Id> &saddles)
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "===================" << endl;
cout << "Compute Chain Graph" << endl;
cout << "===================" << endl;
cout << endl;
#endif
DebugPrint("Chain Graph Computation Starting");
// loop until we run out of active edges
nIterations = 0;
while (edgeSorter.GetNumberOfValues() > 0)
{
// find & label the extrema with their governing saddles
FindGoverningSaddles();
// label the regular points
TransferRegularPoints();
// compact the active set of vertices & edges
CompactActiveVertices();
CompactActiveEdges();
// rebuild the chains
BuildChains();
// choose the subset of edges for the governing saddles
TransferSaddleStarts();
// increment the iteration count
nIterations++;
} // main loop
// final pass to label the trunk vertices
BuildTrunk();
// we can now release many of the arrays to free up space
firstEdge.ReleaseResources();
outdegree.ReleaseResources();
edgeNear.ReleaseResources();
edgeFar.ReleaseResources();
activeEdges.ReleaseResources();
activeVertices.ReleaseResources();
edgeSorter.ReleaseResources();
// and transfer results to mergearcs
TransferToMergeTree(saddles);
// then release the remaining memory
chainExtremum.ReleaseResources();
prunesTo.ReleaseResources();
#ifdef DEBUG_PRINT
DebugPrint("Chain Graph Computed");
#endif
} // Compute()
// sorts saddle ascents to find governing saddles
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::FindGoverningSaddles()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "======================" << endl;
cout << "Find Governing Saddles" << endl;
cout << "======================" << endl;
cout << endl;
#endif
// sort with the comparator
DeviceAlgorithm::Sort(edgeSorter,
EdgePeakComparator<T,StorageType,DeviceAdapter>(
values.PrepareForInput(device),
valueIndex.PrepareForInput(device),
edgeFar.PrepareForInput(device),
edgeNear.PrepareForInput(device),
arcArray.PrepareForInput(device),
isJoinGraph));
#ifdef DEBUG_PRINT
DebugPrint("After Sorting");
#endif
// now loop through the edges
GoverningSaddleFinder governingSaddleFinder;
vtkm::worklet::DispatcherMapField<GoverningSaddleFinder>
governingSaddleFinderDispatcher(governingSaddleFinder);
vtkm::Id nEdges = edgeSorter.GetNumberOfValues();
vtkm::cont::ArrayHandleIndex edgeIndexArray(nEdges);
governingSaddleFinderDispatcher.Invoke(edgeIndexArray, // input
edgeSorter, // input (whole array)
edgeFar, // input (whole array)
edgeNear, // input (whole array)
prunesTo, // output (whole array)
outdegree); // output (whole array)
#ifdef DEBUG_PRINT
DebugPrint(DEBUG_STRING_TRANSFER_GOVERNING_SADDLES);
#endif
} // FindGoverningSaddles()
// marks now regular points for removal
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::TransferRegularPoints()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "=======================" << endl;
cout << "Transfer Regular Points" << endl;
cout << "=======================" << endl;
cout << endl;
#endif
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
RegularPointTransferrer<T> regularPointTransferrer(isJoinGraph);
vtkm::worklet::DispatcherMapField<RegularPointTransferrer<T> >
regularPointTransferrerDispatcher(regularPointTransferrer);
regularPointTransferrerDispatcher.Invoke(activeVertices, // input
chainExtremum, // input (whole array)
values, // input (whole array)
valueIndex, // input (whole array)
prunesTo, // i/o (whole array)
outdegree); // output (whole array)
#ifdef DEBUG_PRINT
DebugPrint("Regular Points Should Now Be Labelled");
#endif
} // TransferRegularPoints()
// compacts the active vertex list
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::CompactActiveVertices()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "=======================" << endl;
cout << "Compact Active Vertices" << endl;
cout << "=======================" << endl;
cout << endl;
#endif
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdArrayType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, IdArrayType> PermuteIndexType;
// retrieve the logical number of vertices
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
// create a temporary array the same size
vtkm::cont::ArrayHandle<vtkm::Id> newActiveVertices;
// Use only the current activeVertices outdegree to match size on StreamCompact
vtkm::cont::ArrayHandle<vtkm::Id> outdegreeLookup;
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, outdegree), outdegreeLookup);
// compact the activeVertices array to keep only the ones of interest
DeviceAlgorithm::StreamCompact(activeVertices, outdegreeLookup, newActiveVertices);
activeVertices.ReleaseResources();
DeviceAlgorithm::Copy(newActiveVertices, activeVertices);
#ifdef DEBUG_PRINT
DebugPrint("Active Vertex List Compacted");
#endif
} // CompactActiveVertices()
// compacts the active edge list
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::CompactActiveEdges()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "====================" << endl;
cout << "Compact Active Edges" << endl;
cout << "====================" << endl;
cout << endl;
#endif
// grab the size of the array for easier reference
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
// first, we have to work out the first edge for each active vertex
// we start with a temporary new updegree
vtkm::cont::ArrayHandle<vtkm::Id> newOutdegree;
newOutdegree.Allocate(nActiveVertices);
// do a parallel computation using the vertex degree updater
// WARNING: Using chainMaximum for I/O in parallel loop
// See functor description for algorithmic justification of safety
VertexDegreeUpdater vertexDegreeUpdater;
vtkm::worklet::DispatcherMapField<VertexDegreeUpdater>
vertexDegreeUpdaterDispatcher(vertexDegreeUpdater);
vertexDegreeUpdaterDispatcher.Invoke(activeVertices, // input
activeEdges, // input (whole array)
edgeFar, // input (whole array)
firstEdge, // input (whole array)
prunesTo, // input (whole array)
outdegree, // input (whole array)
chainExtremum, // i/o (whole array)
newOutdegree); // output
// now we do a reduction to compute the offsets of each vertex
vtkm::cont::ArrayHandle<vtkm::Id> newPosition;
DeviceAlgorithm::ScanExclusive(newOutdegree, newPosition);
vtkm::Id nNewEdges = newPosition.GetPortalControl().Get(nActiveVertices-1) +
newOutdegree.GetPortalControl().Get(nActiveVertices-1);
// create a temporary vector for copying
vtkm::cont::ArrayHandle<vtkm::Id> newActiveEdges;
newActiveEdges.Allocate(nNewEdges);
// now copy the relevant edges into the active edge array
// WARNING: Using chainMaximum, edgeHigh, firstEdge, updegree for I/O in parallel loop
// See functor description for algorithmic justification of safety
ActiveEdgeTransferrer<DeviceAdapter> activeEdgeTransferrer(
activeEdges.PrepareForInput(device),
prunesTo.PrepareForInput(device));
vtkm::worklet::DispatcherMapField<ActiveEdgeTransferrer<DeviceAdapter> >
activeEdgeTransferrerDispatcher(activeEdgeTransferrer);
activeEdgeTransferrerDispatcher.Invoke(activeVertices, // input
newPosition, // input
newOutdegree, // input
firstEdge, // i/o (whole array)
outdegree, // i/o (whole array)
chainExtremum, // i/o (whole array)
edgeFar, // i/o (whole array)
newActiveEdges); // output (whole array)
// resize the original array and recopy
DeviceAlgorithm::Copy(newActiveEdges, activeEdges);
#ifdef DEBUG_PRINT
DebugPrint("Active Edges Now Compacted");
#endif
} // CompactActiveEdges()
// builds the chains for the new active vertices
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::BuildChains()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "============" << endl;
cout << "Build Chains" << endl;
cout << "============" << endl;
cout << endl;
#endif
// a temporary array the full size of the graph
vtkm::cont::ArrayHandle<vtkm::Id> tempChainExtremum;
tempChainExtremum.Allocate(edgeNear.GetNumberOfValues());
// compute the number of log steps required in this pass
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
vtkm::Id nLogSteps = 1;
for (vtkm::Id shifter = nActiveVertices; shifter != 0; shifter >>= 1)
nLogSteps++;
ChainDoubler chainDoubler;
vtkm::worklet::DispatcherMapField<ChainDoubler> chainDoublerDispatcher(chainDoubler);
// 2. Use path compression / step doubling to collect vertices along ascending chains
// until every vertex has been assigned to *an* extremum
// Step two at a time, so that we rock between the original and the temp
for (vtkm::Id logStep = 0; logStep < nLogSteps; logStep++)
{
chainDoublerDispatcher.Invoke(activeVertices, // input
chainExtremum); // i/o (whole array)
}
#ifdef DEBUG_PRINT
DebugPrint("Chains Built");
#endif
} // BuildChains()
// transfers saddle ascent edges into edge sorter
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::TransferSaddleStarts()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "=======================" << endl;
cout << DEBUG_STRING_TRANSFER_SADDLE_STARTS << endl;
cout << "=======================" << endl;
cout << endl;
#endif
// grab the size of the array for easier reference
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
// reset number of edges to sort
vtkm::Id nEdgesToSort = 0;
// in parallel, we need to create a vector to count the first edge for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> newFirstEdge;
vtkm::cont::ArrayHandle<vtkm::Id> newOutdegree;
newFirstEdge.Allocate(nActiveVertices);
newOutdegree.Allocate(nActiveVertices);
// 2. now test all active vertices to see if they have only one chain maximum
SaddleAscentFunctor saddleAscentFunctor;
vtkm::worklet::DispatcherMapField<SaddleAscentFunctor>
saddleAscentFunctorDispatcher(saddleAscentFunctor);
saddleAscentFunctorDispatcher.Invoke(activeVertices, // input
firstEdge, // input (whole array)
outdegree, // input (whole array)
activeEdges, // input (whole array)
chainExtremum, // input (whole array)
edgeFar, // input (whole array)
newOutdegree); // output
// 3. now compute the new offsets in the newFirstEdge array
DeviceAlgorithm::ScanExclusive(newOutdegree, newFirstEdge);
nEdgesToSort = newFirstEdge.GetPortalControl().Get(nActiveVertices-1) +
newOutdegree.GetPortalControl().Get(nActiveVertices-1);
edgeSorter.ReleaseResources();
edgeSorter.Allocate(nEdgesToSort);
SaddleAscentTransferrer saddleAscentTransferrer;
vtkm::worklet::DispatcherMapField<SaddleAscentTransferrer>
saddleAscentTransferrerDispatcher(saddleAscentTransferrer);
saddleAscentTransferrerDispatcher.Invoke(activeVertices, // input
newOutdegree, // input
newFirstEdge, // input
activeEdges, // input (whole array)
firstEdge, // input (whole array)
edgeSorter); // output (whole array)
#ifdef DEBUG_PRINT
DebugPrint(DEBUG_STRING_TRANSFERRED_SADDLE_STARTS);
#endif
} // TransferSaddleStarts()
// sets all remaining active vertices
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::BuildTrunk()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "===========" << endl;
cout << "Build Trunk" << endl;
cout << "============" << endl;
cout << endl;
#endif
TrunkBuilder trunkBuilder;
vtkm::worklet::DispatcherMapField<TrunkBuilder>
trunkBuilderDispatcher(trunkBuilder);
trunkBuilderDispatcher.Invoke(activeVertices, // input
chainExtremum, // input (whole array)
prunesTo); // output (whole array)
#ifdef DEBUG_PRINT
DebugPrint("Trunk Built");
#endif
} // BuildTrunk()
// transfers partial results to merge tree array
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::TransferToMergeTree(vtkm::cont::ArrayHandle<vtkm::Id> &saddles)
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "=====================" << endl;
cout << DEBUG_STRING_TRANSFER_TO_MERGE_TREE << endl;
cout << "=====================" << endl;
cout << endl;
#endif
// first allocate memory for the target array
saddles.ReleaseResources();
// initialise it to the arcArray
DeviceAlgorithm::Copy(arcArray, saddles);
JoinTreeTransferrer joinTreeTransferrer;
vtkm::worklet::DispatcherMapField<JoinTreeTransferrer>
joinTreeTransferrerDispatcher(joinTreeTransferrer);
vtkm::cont::ArrayHandleIndex valueIndexArray(valueIndex.GetNumberOfValues());
joinTreeTransferrerDispatcher.Invoke(valueIndexArray, // input
prunesTo, // input
valueIndex, // input (whole array)
chainExtremum, // input (whole array)
saddles, // output (whole array)
arcArray); // output (whole array)
} // TransferToMergeTree()
// prints the contents of the topology graph in standard format
template<typename T, typename StorageType, typename DeviceAdapter>
void ChainGraph<T,StorageType,DeviceAdapter>::DebugPrint(const char *message)
{
std::cout << "---------------------------" << std::endl;
std::cout << string(message) << std::endl;
std::cout << "---------------------------" << std::endl;
std::cout << std::endl;
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdArrayType;
typedef vtkm::cont::ArrayHandle<T> ValueArrayType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, IdArrayType> PermuteIndexType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> PermuteValueType;
// Full Vertex Arrays
vtkm::Id nValues = valueIndex.GetNumberOfValues();
vtkm::cont::ArrayHandle<T,StorageType> vertexValues;
std::cout << "Full Vertex Arrays - Size: " << nValues << std::endl;
printHeader(nValues);
printIndices("Index", valueIndex);
DeviceAlgorithm::Copy(PermuteValueType(valueIndex, values), vertexValues);
printValues("Value", vertexValues);
printIndices("First Edge", firstEdge);
printIndices("Outdegree", outdegree);
printIndices("Chain Ext", chainExtremum);
printIndices("Prunes To", prunesTo);
std::cout << endl;
// Active Vertex Arrays
vtkm::Id nActiveVertices = activeVertices.GetNumberOfValues();
std::cout << "Active Vertex Arrays - Size: " << nActiveVertices << std::endl;
if (nActiveVertices > 0) {
vtkm::cont::ArrayHandle<vtkm::Id> tempIndex;
vtkm::cont::ArrayHandle<T> tempValue;
printHeader(nActiveVertices);
printIndices("Active Vertices", activeVertices);
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, valueIndex), tempIndex);
printIndices("Active Indices", tempIndex);
DeviceAlgorithm::Copy(PermuteValueType(activeVertices, vertexValues), tempValue);
printValues("Active Values", tempValue);
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, firstEdge), tempIndex);
printIndices("Active First Edge", tempIndex);
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, outdegree), tempIndex);
printIndices("Active Outdegree", tempIndex);
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, chainExtremum), tempIndex);
printIndices("Active Chain Ext", tempIndex);
DeviceAlgorithm::Copy(PermuteIndexType(activeVertices, prunesTo), tempIndex);
printIndices("Active Prunes To", tempIndex);
std::cout << endl;
}
// Full Edge Arrays
vtkm::Id nEdges = edgeNear.GetNumberOfValues();
std::cout << "Full Edge Arrays - Size: " << nEdges << std::endl;
vtkm::cont::ArrayHandle<vtkm::Id> farIndices;
vtkm::cont::ArrayHandle<vtkm::Id> nearIndices;
vtkm::cont::ArrayHandle<T,StorageType> farValues;
vtkm::cont::ArrayHandle<T,StorageType> nearValues;
if (nEdges > 0) {
printHeader(nEdges);
printIndices("Far", edgeFar);
DeviceAlgorithm::Copy(PermuteIndexType(edgeFar, valueIndex), farIndices);
printIndices("Far Index", farIndices);
DeviceAlgorithm::Copy(PermuteValueType(farIndices, values), farValues);
printValues("Far Value", farValues);
printHeader(nEdges);
printIndices("Near", edgeNear);
DeviceAlgorithm::Copy(PermuteIndexType(edgeNear, valueIndex), nearIndices);
printIndices("Near Index", nearIndices);
DeviceAlgorithm::Copy(PermuteValueType(nearIndices, values), nearValues);
printValues("Near Value", nearValues);
}
// Active Edge Arrays
vtkm::Id nActiveEdges = activeEdges.GetNumberOfValues();
std::cout << "Active Edge Arrays - Size: " << nActiveEdges << std::endl;
if (nActiveEdges > 0) {
vtkm::cont::ArrayHandle<vtkm::Id> activeFarIndices;
vtkm::cont::ArrayHandle<vtkm::Id> activeNearIndices;
vtkm::cont::ArrayHandle<vtkm::Id> activeNearLookup;
vtkm::cont::ArrayHandle<T,StorageType> activeNearValues;
printHeader(nActiveEdges);
printIndices("Active Edges", activeEdges);
DeviceAlgorithm::Copy(PermuteIndexType(activeEdges, edgeFar), activeFarIndices);
printIndices("Edge Far", activeFarIndices);
DeviceAlgorithm::Copy(PermuteIndexType(activeEdges, edgeNear), activeNearIndices);
printIndices("Edge Near", activeNearIndices);
DeviceAlgorithm::Copy(PermuteIndexType(activeNearIndices, valueIndex), activeNearLookup);
printIndices("Edge Near Index", activeNearLookup);
DeviceAlgorithm::Copy(PermuteValueType(activeNearLookup, values), activeNearValues);
printValues("Edge Near Value", activeNearValues);
std::cout << endl;
}
// Edge Sorter Array
vtkm::Id nEdgeSorter = edgeSorter.GetNumberOfValues();
std::cout << "Edge Sorter - Size: " << nEdgeSorter << std::endl;
if (nEdgeSorter > 0) {
vtkm::cont::ArrayHandle<vtkm::Id> tempSortIndex;
vtkm::cont::ArrayHandle<T> tempSortValue;
printHeader(nEdgeSorter);
printIndices("Edge Sorter", edgeSorter);
DeviceAlgorithm::Copy(PermuteIndexType(edgeSorter, edgeNear), tempSortIndex);
printIndices("Sorted Near", tempSortIndex);
DeviceAlgorithm::Copy(PermuteIndexType(edgeSorter, nearIndices), tempSortIndex);
printIndices("Sorted Near Index", tempSortIndex);
DeviceAlgorithm::Copy(PermuteIndexType(edgeSorter, edgeFar), tempSortIndex);
printIndices("Sorted Far", tempSortIndex);
DeviceAlgorithm::Copy(PermuteValueType(edgeSorter, nearValues), tempSortValue);
printValues("Sorted Near Value", tempSortValue);
std::cout << endl;
}
std::cout << "---------------------------" << std::endl;
std::cout << endl;
} // DebugPrint()
}
}
}
#endif

@ -0,0 +1,943 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// ContourTree.h - class representing the contour tree
//
//=======================================================================================
//
// COMMENTS:
//
//
// i.e. based on PeakPitPruningCriticalSerial
//
// Under the old merge approach, we had an essentially breadth-first queue for transferring
// leaves from the merge trees to the contour tree.
//
// Most of these leaves are completely independent of each other, and can (on principle)
// be processed simultaneously. However, the interior of the tree is dependent on them
// having been dealt with already. This version, therefore, will make multiple passes,
// in each pass pruning all maxima then all minima, interspersed with updating the merge
// and split trees. To understand this, consider what happens in the merge algorithm when
// a maximum is added:
//
// 1. The vertex v is removed from the queue: it has one join neighbour, w
// 2. Edge (v,w) is removed from the join tree, along with vertex v
// 3. Edge (v,w) is added to the contour tree, with v, w if necessary
// 4. Vertex v is removed from the split tree, bridging edges past it if necessary
// 5. Vertex w is added to the queue iff it is now a leaf
//
// To parallelise this:
// For all vertices v
// Set contourArc[v] = NO_VERTEX_ASSIGNED
// Set nContourArcs = 0;
// While (nContourArcs) > 0 // might be one, or something else - base case isn't clear
// a. Use reduction to compute updegree from join tree, downdegree from split tree
// b. For each vertex v
// // omit previously processed vertices
// if (contourArc[v] == NO_VERTEX_ASSIGNED)
// continue;
// // Test for extremality
// i. If ((updegree[v] == 0) && (downdegree[v] == 1))
// { // Maximum
// contourArc[v] = joinArc[v];
// } // Maximum
// ii. Else if ((updegree[v] = 1) && (downdegree[v] == 0))
// { // Minimum
// contourArc[v] = splitArc[v];
// } // Minimum
// c. For (log n iterations)
// i. For each vertex v
// retrieve it's join neighbour j
// retrieve it's split neighbour s
// if v has no join neighbour (i.e. j == -1)
// skip (i.e. v is the root)
// else if j has a contour arc assigned
// set v's neighbour to j's neighbour
// if v has no split neighbour (i.e. s == -1)
// skip (i.e. v is the root)
// else if s has a contour arc assigned
// set v's neighbour to s's neighbour
//
// Initially, we will do this with all vertices, regular or otherwise, then restrict to
// the critical points. Number of iterations - regular vertices will slow this down, so
// the worst case is O(n) passes. Even if we restrict to critical points, W's in the tree
// will serialise, so O(n) still applies. I believe that the W edges can be suppressed,
// but let's leave that to optimisation for now.
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_contourtree_h
#define vtkm_worklet_contourtree_contourtree_h
// local includes
#include <vtkm/worklet/contourtree/MergeTree.h>
#include <vtkm/worklet/contourtree/ChainGraph.h>
#include <vtkm/worklet/contourtree/PrintVectors.h>
#include <vtkm/worklet/contourtree/Types.h>
#include <vtkm/worklet/contourtree/RegularToCriticalUp.h>
#include <vtkm/worklet/contourtree/RegularToCriticalDown.h>
#include <vtkm/worklet/contourtree/RegularToCandidate.h>
#include <vtkm/worklet/contourtree/SubrangeOffset.h>
#include <vtkm/worklet/contourtree/DegreeDelta.h>
#include <vtkm/worklet/contourtree/FillSupernodes.h>
#include <vtkm/worklet/contourtree/CopySupernodes.h>
#include <vtkm/worklet/contourtree/SetJoinAndSplitArcs.h>
#include <vtkm/worklet/contourtree/FindLeaves.h>
#include <vtkm/worklet/contourtree/CopyJoinSplit.h>
#include <vtkm/worklet/contourtree/UpdateOutbound.h>
#include <vtkm/worklet/contourtree/SetSupernodeInward.h>
#include <vtkm/worklet/contourtree/SkipVertex.h>
#include <vtkm/worklet/contourtree/CopyNeighbors.h>
#include <vtkm/worklet/contourtree/ResetDegrees.h>
#include <vtkm/worklet/contourtree/DegreeSubrangeOffset.h>
#include <vtkm/Pair.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
#include <vtkm/worklet/WorkletMapField.h>
#define DEBUG_PRINT 1
//#define DEBUG_TIMING 1
namespace vtkm {
namespace worklet {
namespace contourtree {
template <typename T, typename StorageType, typename DeviceAdapter>
class ContourTree
{
public:
typedef typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter> DeviceAlgorithm;
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdArrayType;
typedef vtkm::cont::ArrayHandle<T> ValueArrayType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, IdArrayType> PermuteIndexType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> PermuteValueType;
// device
DeviceAdapter device;
// reference to the underlying data
const vtkm::cont::ArrayHandle<T,StorageType> values;
// vector of superarcs in the contour tree (stored as inward-pointing)
vtkm::cont::ArrayHandle<vtkm::Id> superarcs;
// vector of supernodes
vtkm::cont::ArrayHandle<vtkm::Id> supernodes;
// vector of supernodes still unprocessed
vtkm::cont::ArrayHandle<vtkm::Id> activeSupernodes;
// references to join & split trees
MergeTree<T,StorageType,DeviceAdapter> &joinTree, &splitTree;
// references to join & split graphs
ChainGraph<T,StorageType,DeviceAdapter> &joinGraph, &splitGraph;
// vectors of up & down degree used during computation
vtkm::cont::ArrayHandle<vtkm::Id> updegree, downdegree;
// vectors for tracking merge arcs
vtkm::cont::ArrayHandle<vtkm::Id> joinArcs, splitArcs;
// counter for how many iterations it took to compute
vtkm::Id nIterations;
// contour tree constructor
ContourTree(const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
MergeTree<T,StorageType,DeviceAdapter> &JoinTree,
ChainGraph<T,StorageType,DeviceAdapter> &JoinGraph,
MergeTree<T,StorageType,DeviceAdapter> &SplitTree,
ChainGraph<T,StorageType,DeviceAdapter> &SplitGraph);
// routines for computing the contour tree
// combines the list of active vertices for join & split trees
// then reduces them to eliminate regular vertices & non-connectivity critical points
void FindSupernodes();
// transfers leaves from join/split trees to contour tree
void TransferLeaves();
// collapses regular edges along leaf superarcs
void CollapseRegular(bool isJoin);
// compresses trees to remove transferred vertices
void CompressTrees();
// compresses active set of supernodes
void CompressActiveSupernodes();
// finds the degree of each supernode from the join & split trees
void FindDegrees();
// collect the resulting saddle peaks in sort pairs
void CollectSaddlePeak(vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > &saddlePeak);
void DebugPrint(const char *message);
}; // class ContourTree
struct VertexAssigned : vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> supernode,
WholeArrayIn<IdType> superarcs,
FieldOut<IdType> hasSuperArc);
typedef _3 ExecutionSignature(_1, _2);
typedef _1 InputDomain;
bool vertexIsAssigned;
VTKM_EXEC_CONT
VertexAssigned(bool VertexIsAssigned) : vertexIsAssigned(VertexIsAssigned) {}
template <typename InPortalFieldType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id supernode,
const InPortalFieldType& superarcs) const
{
if (vertexIsAssigned == false)
{
if (superarcs.Get(supernode) == NO_VERTEX_ASSIGNED)
return vtkm::Id(1);
else
return vtkm::Id(0);
}
else
{
if (superarcs.Get(supernode) != NO_VERTEX_ASSIGNED)
return vtkm::Id(1);
else
return vtkm::Id(0);
}
}
};
// creates contour tree
template <typename T, typename StorageType, typename DeviceAdapter>
ContourTree<T,StorageType,DeviceAdapter>::ContourTree(
const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
MergeTree<T,StorageType,DeviceAdapter> &JoinTree,
ChainGraph<T,StorageType,DeviceAdapter> &JoinGraph,
MergeTree<T,StorageType,DeviceAdapter> &SplitTree,
ChainGraph<T,StorageType,DeviceAdapter> &SplitGraph)
: values(Values),
device(Device),
joinTree(JoinTree),
joinGraph(JoinGraph),
splitTree(SplitTree),
splitGraph(SplitGraph)
{
// first we have to get the correct list of supernodes
// this will also set the degrees of the vertices initially
FindSupernodes();
// set the active vertices to something greater than 0 for the loop
vtkm::Id nActiveVertices = supernodes.GetNumberOfValues();
// and track how many iterations it takes
nIterations = 0;
// loop until no arcs remaining to be found
// tree can end with either 0 or 1 vertices unprocessed
// 0 means the last edge was pruned from both ends
// 1 means that there were two final edges meeting at a vertex
while (activeSupernodes.GetNumberOfValues() > 1)
{ // loop until no active vertices remaining
#ifdef DEBUG_PRINT
std::cout << "========================================" << std::endl;
std::cout << " " << std::endl;
std::cout << "Iteration " << nIterations << " Size " << activeSupernodes.GetNumberOfValues() << std::endl;
std::cout << " " << std::endl;
std::cout << "========================================" << std::endl;
#endif
// transfer all leaves to the contour tree
TransferLeaves();
// collapse regular vertices from leaves, upper then lower
CollapseRegular(true);
CollapseRegular(false);
// compress the join and split trees
CompressTrees();
// compress the active list of supernodes
CompressActiveSupernodes();
// recompute the vertex degrees
FindDegrees();
nIterations++;
}
} // constructor
// combines the list of active vertices for join & split trees
// then reduces them to eliminate regular vertices & non-connectivity critical points
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::FindSupernodes()
{
// both trees may have non-connectivity critical points, so we first make a joint list
// here, we will explicitly assume that the active lists are in numerical order
// which is how we are currently constructing them
vtkm::Id nCandidates = joinGraph.valueIndex.GetNumberOfValues() +
splitGraph.valueIndex.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::Id> candidates;
// take the union of the two sets of vertices
vtkm::cont::ArrayHandleConcatenate<IdArrayType, IdArrayType> candidateArray(joinGraph.valueIndex, splitGraph.valueIndex);
DeviceAlgorithm::Copy(candidateArray, candidates);
DeviceAlgorithm::Sort(candidates);
DeviceAlgorithm::Unique(candidates);
nCandidates = candidates.GetNumberOfValues();
vtkm::cont::ArrayHandleIndex candidateIndexArray(nCandidates);
// we need an array lookup to convert vertex ID's
vtkm::Id nValues = values.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::Id> regularToCritical;
vtkm::cont::ArrayHandleConstant<vtkm::Id> noVertArray(NO_VERTEX_ASSIGNED, nValues);
DeviceAlgorithm::Copy(noVertArray, regularToCritical);
if (nCandidates > 0) {
RegularToCriticalUp regularToCriticalUp;
vtkm::worklet::DispatcherMapField<RegularToCriticalUp>
regularToCriticalUpDispatcher(regularToCriticalUp);
regularToCriticalUpDispatcher.Invoke(candidateIndexArray, // input
candidates, // input
regularToCritical); // output (whole array)
}
// now that we have a complete list of active nodes from each, we can call the trees
// to connect them properly
joinTree.ComputeAugmentedSuperarcs();
joinTree.ComputeAugmentedArcs(candidates);
splitTree.ComputeAugmentedSuperarcs();
splitTree.ComputeAugmentedArcs(candidates);
// we create up & down degree arrays
vtkm::cont::ArrayHandleConstant<vtkm::Id> initCandidateArray(0, nCandidates);
vtkm::cont::ArrayHandle<vtkm::Id> upCandidate;
vtkm::cont::ArrayHandle<vtkm::Id> downCandidate;
DeviceAlgorithm::Copy(initCandidateArray, upCandidate);
DeviceAlgorithm::Copy(initCandidateArray, downCandidate);
// This next chunk changes in parallel - it has to count the up & down degree for each
// vertex. It's a simple loop in serial, but in parallel, what we have to do is:
// 1. Copy the lower ends of the edges, converting from regular ID to candidate ID
// 2. Sort the lower ends of the edges
// 3. For each value, store the beginning of the range
// 4. Compute the delta to get the degree.
// create a sorting vector
vtkm::cont::ArrayHandle<vtkm::Id> sortVector;
sortVector.Allocate(nCandidates);
// 1. Copy the lower ends of the edges, converting from regular ID to candidate ID
if (nCandidates > 0) {
RegularToCandidate regularToCandidate;
vtkm::worklet::DispatcherMapField<RegularToCandidate>
regularToCandidateDispatcher(regularToCandidate);
regularToCandidateDispatcher.Invoke(candidates, // input
joinTree.mergeArcs, // input (whole array)
regularToCritical, // input (whole array)
sortVector); // output
}
// 2. Sort the lower ends of the edges
DeviceAlgorithm::Sort(sortVector);
// 3. For each value, store the beginning & end of the range (in parallel)
// The 0th element is guaranteed to be NO_VERTEX_ASSIGNED, & can be skipped
// Otherwise, if the i-1th element is different, we are the offset for the subrange
// and store into the ith place
vtkm::cont::ArrayHandleCounting<vtkm::Id> subsetIndexArray(1, 1, nCandidates-1);
if (nCandidates > 0) {
SubrangeOffset subRangeOffset;
vtkm::worklet::DispatcherMapField<SubrangeOffset>
subrangeOffsetDispatcher(subRangeOffset);
subrangeOffsetDispatcher.Invoke(subsetIndexArray, // index
sortVector, // input
upCandidate); // output
}
// 4. Compute the delta to get the degree.
if (nCandidates > 0) {
DegreeDelta degreeDelta(nCandidates);
vtkm::worklet::DispatcherMapField<DegreeDelta>
degreeDeltaDispatcher(degreeDelta);
degreeDeltaDispatcher.Invoke(subsetIndexArray, // input
sortVector, // input (whole array)
upCandidate); // output (whole array)
}
// Now repeat the same steps for the downdegree
// 1. Copy the upper ends of the edges, converting from regular ID to candidate ID
if (nCandidates > 0) {
RegularToCriticalDown regularToCriticalDown;
vtkm::worklet::DispatcherMapField<RegularToCriticalDown>
regularToCriticalDownDispatcher(regularToCriticalDown);
regularToCriticalDownDispatcher.Invoke(candidates, // input
splitTree.mergeArcs, // input (whole array)
regularToCritical, // input (whole array)
sortVector); // output
}
// 2. Sort the lower ends of the edges
DeviceAlgorithm::Sort(sortVector);
// 3. For each value, store the beginning & end of the range (in parallel)
// The 0th element is guaranteed to be NO_VERTEX_ASSIGNED, & can be skipped
// Otherwise, if the i-1th element is different, we are the offset for the subrange
// and store into the ith place
if (nCandidates > 0) {
SubrangeOffset subRangeOffset;
vtkm::worklet::DispatcherMapField<SubrangeOffset>
subrangeOffsetDispatcher(subRangeOffset);
subrangeOffsetDispatcher.Invoke(subsetIndexArray, // index
sortVector, // input
downCandidate); // output
}
// 4. Compute the delta to get the degree.
if (nCandidates > 0) {
DegreeDelta degreeDelta(nCandidates);
vtkm::worklet::DispatcherMapField<DegreeDelta>
degreeDeltaDispatcher(degreeDelta);
degreeDeltaDispatcher.Invoke(subsetIndexArray, // index
sortVector, // input
downCandidate); // in out
}
// create an index vector for whether the vertex is to be kept
vtkm::cont::ArrayHandle<vtkm::Id> isSupernode;
isSupernode.Allocate(nCandidates);
// fill the vector in
if (nCandidates > 0) {
FillSupernodes fillSupernodes;
vtkm::worklet::DispatcherMapField<FillSupernodes>
fillSupernodesDispatcher(fillSupernodes);
fillSupernodesDispatcher.Invoke(upCandidate, // input
downCandidate, // input
isSupernode); // output
}
// do a compaction to find the new index for each
// We end with 0 in position 0, and need one extra position to find the new size
vtkm::cont::ArrayHandle<vtkm::Id> supernodeID;
DeviceAlgorithm::ScanExclusive(isSupernode, supernodeID);
// size is the position of the last element + the size of the last element (0/1)
vtkm::Id nSupernodes = supernodeID.GetPortalConstControl().Get(nCandidates-1) +
isSupernode.GetPortalConstControl().Get(nCandidates-1);
// allocate memory for our arrays
supernodes.ReleaseResources();
updegree.ReleaseResources();
downdegree.ReleaseResources();
supernodes.Allocate(nSupernodes);
updegree.Allocate(nSupernodes);
downdegree.Allocate(nSupernodes);
// now copy over the positions to compact
if (nCandidates > 0) {
CopySupernodes copySupernodes;
vtkm::worklet::DispatcherMapField<CopySupernodes>
copySupernodesDispatcher(copySupernodes);
copySupernodesDispatcher.Invoke(isSupernode, // input
candidates, // input
supernodeID, // input
upCandidate, // input
downCandidate, // input
regularToCritical, // output (whole array)
supernodes, // output (whole array)
updegree, // output (whole array)
downdegree); // output (whole array)
}
// now we call the merge tree again to reset the merge arcs
joinTree.ComputeAugmentedArcs(supernodes);
splitTree.ComputeAugmentedArcs(supernodes);
// next we create the working arrays of merge arcs
nSupernodes = supernodes.GetNumberOfValues();
vtkm::cont::ArrayHandleIndex supernodeIndexArray(nSupernodes);
joinArcs.ReleaseResources();
splitArcs.ReleaseResources();
joinArcs.Allocate(nSupernodes);
splitArcs.Allocate(nSupernodes);
// and copy them across, setting IDs for both ends
SetJoinAndSplitArcs setJoinAndSplitArcs;
vtkm::worklet::DispatcherMapField<SetJoinAndSplitArcs>
setJoinAndSplitArcsDispatcher(setJoinAndSplitArcs);
setJoinAndSplitArcsDispatcher.Invoke(supernodes, // input
joinTree.mergeArcs, // input (whole array)
splitTree.mergeArcs, // input (whole array)
regularToCritical, // input (whole array)
joinArcs, // output
splitArcs); // output
vtkm::cont::ArrayHandleConstant<vtkm::Id> newsuperarcs(NO_VERTEX_ASSIGNED, nSupernodes);
superarcs.ReleaseResources();
DeviceAlgorithm::Copy(newsuperarcs, superarcs);
// create the active supernode vector
activeSupernodes.ReleaseResources();
activeSupernodes.Allocate(nSupernodes);
vtkm::cont::ArrayHandleIndex supernodeSeq(nSupernodes);
DeviceAlgorithm::Copy(supernodeSeq, activeSupernodes);
#ifdef DEBUG_PRINT
DebugPrint("Supernodes Found");
#endif
} // FindSupernodes()
// transfers leaves from join/split trees to contour tree
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::TransferLeaves()
{
FindLeaves findLeaves;
vtkm::worklet::DispatcherMapField<FindLeaves>
findLeavesDispatcher(findLeaves);
findLeavesDispatcher.Invoke(activeSupernodes, // input
updegree, // input (whole array)
downdegree, // input (whole array)
joinArcs, // input (whole array)
splitArcs, // input (whole array)
superarcs); // i/o (whole array)
#ifdef DEBUG_PRINT
DebugPrint("Leaves Transferred");
#endif
} // TransferLeaves()
// collapses regular edges along leaf superarcs
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::CollapseRegular(bool isJoin)
{
// we'll have a vector for tracking outwards
vtkm::Id nSupernodes = supernodes.GetNumberOfValues();
vtkm::cont::ArrayHandleConstant<vtkm::Id> nullArray(0, nSupernodes);
vtkm::cont::ArrayHandle<vtkm::Id> outbound;
outbound.Allocate(nSupernodes);
DeviceAlgorithm::Copy(nullArray, outbound);
// and a reference for the inwards array and to the degrees
vtkm::cont::ArrayHandle<vtkm::Id> inbound;
vtkm::cont::ArrayHandle<vtkm::Id> indegree;
vtkm::cont::ArrayHandle<vtkm::Id> outdegree;
if (isJoin) {
DeviceAlgorithm::Copy(joinArcs, inbound);
DeviceAlgorithm::Copy(downdegree, indegree);
DeviceAlgorithm::Copy(updegree, outdegree);
}
else {
DeviceAlgorithm::Copy(splitArcs, inbound);
DeviceAlgorithm::Copy(updegree, indegree);
DeviceAlgorithm::Copy(downdegree, outdegree);
}
// loop to copy join/split
CopyJoinSplit copyJoinSplit;
vtkm::worklet::DispatcherMapField<CopyJoinSplit>
copyJoinSplitDispatcher(copyJoinSplit);
copyJoinSplitDispatcher.Invoke(activeSupernodes, // input
inbound, // input (whole array)
indegree, // input (whole array)
outdegree, // input (whole array)
outbound); // output (whole array)
// Compute the number of log steps required in this pass
vtkm::Id nLogSteps = 1;
vtkm::Id nActiveSupernodes = activeSupernodes.GetNumberOfValues();
for (vtkm::Id shifter = nActiveSupernodes; shifter != 0; shifter >>= 1)
nLogSteps++;
// loop to find the now-regular vertices and collapse past them without altering
// the existing join & split arcs
for (vtkm::Id iteration = 0; iteration < nLogSteps; iteration++)
{
UpdateOutbound updateOutbound;
vtkm::worklet::DispatcherMapField<UpdateOutbound>
updateOutboundDispatcher(updateOutbound);
updateOutboundDispatcher.Invoke(activeSupernodes, // input
outbound); // i/o (whole array)
}
// at this point, the outbound vector chains everything outwards to the leaf
// any vertices on the last outbound leaf superarc point to the leaf
// Now, any regular leaf vertex points out to a leaf, so the condition we test is
// a. outbound is not -1 (i.e. vertex is regular)
// b. superarc[outbound] is not -1 (i.e. outbound is a leaf)
SetSupernodeInward setSupernodeInward;
vtkm::worklet::DispatcherMapField<SetSupernodeInward>
setSupernodeInwardDispatcher(setSupernodeInward);
setSupernodeInwardDispatcher.Invoke(activeSupernodes, // input
inbound, // input (whole array)
outbound, // input (whole array)
indegree, // input (whole array)
outdegree, // input (whole array)
superarcs); // i/o (whole array)
outbound.ReleaseResources();
#ifdef DEBUG_PRINT
DebugPrint(isJoin ? "Upper Regular Nodes Collapsed" : "Lower Regular Nodes Collapsed");
#endif
} // CollapseRegular()
// compresses trees to remove transferred vertices
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::CompressTrees()
{
// Compute the number of log steps required in this pass
vtkm::Id nActiveSupernodes = activeSupernodes.GetNumberOfValues();
vtkm::Id nLogSteps = 1;
for (vtkm::Id shifter = nActiveSupernodes; shifter != 0; shifter >>= 1)
nLogSteps++;
// loop to update the merge trees
for (vtkm::Id logStep = 0; logStep < nLogSteps; logStep++)
{
SkipVertex skipVertex;
vtkm::worklet::DispatcherMapField<SkipVertex>
skipVertexDispatcher(skipVertex);
skipVertexDispatcher.Invoke(activeSupernodes, // input
superarcs, // input (whole array)
joinArcs, // i/o (whole array)
splitArcs); // i/o (whole array)
}
#ifdef DEBUG_PRINT
DebugPrint("Trees Compressed");
#endif
} // CompressTrees()
// compresses active set of supernodes
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::CompressActiveSupernodes()
{
// copy only if the superarc is not set
vtkm::cont::ArrayHandle<vtkm::Id> noSuperarcArray;
noSuperarcArray.Allocate(activeSupernodes.GetNumberOfValues());
VertexAssigned vertexAssigned(false);
vtkm::worklet::DispatcherMapField<VertexAssigned>
vertexAssignedDispatcher(vertexAssigned);
vertexAssignedDispatcher.Invoke(activeSupernodes,
superarcs,
noSuperarcArray);
vtkm::cont::ArrayHandle<vtkm::Id> compressSupernodes;
DeviceAlgorithm::StreamCompact(activeSupernodes, noSuperarcArray, compressSupernodes);
activeSupernodes.ReleaseResources();
DeviceAlgorithm::Copy(compressSupernodes, activeSupernodes);
#ifdef DEBUG_PRINT
DebugPrint("Active Supernodes Compressed");
#endif
} // CompressActiveSupernodes()
// recomputes the degree of each supernode from the join & split trees
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::FindDegrees()
{
if (activeSupernodes.GetNumberOfValues() == 0)
return;
vtkm::Id nActiveSupernodes = activeSupernodes.GetNumberOfValues();
ResetDegrees resetDegrees;
vtkm::worklet::DispatcherMapField<ResetDegrees>
resetDegreesDispatcher(resetDegrees);
resetDegreesDispatcher.Invoke(activeSupernodes, // input
updegree, // output (whole array)
downdegree); // output (whole array)
// create a temporary sorting array
vtkm::cont::ArrayHandle<vtkm::Id> sortVector;
sortVector.Allocate(nActiveSupernodes);
vtkm::cont::ArrayHandleIndex activeSupernodeIndexArray(nActiveSupernodes);
// 1. Copy the neighbours for each active edge
if (nActiveSupernodes > 0) {
CopyNeighbors copyNeighbors;
vtkm::worklet::DispatcherMapField<CopyNeighbors>
copyNeighborsDispatcher(copyNeighbors);
copyNeighborsDispatcher.Invoke(activeSupernodeIndexArray, // input
activeSupernodes, // input (whole array)
joinArcs, // input (whole array)
sortVector); // output
}
// 2. Sort the neighbours
DeviceAlgorithm::Sort(sortVector);
// 3. For each value, store the beginning & end of the range (in parallel)
// The 0th element is guaranteed to be NO_VERTEX_ASSIGNED, & can be skipped
// Otherwise, if the i-1th element is different, we are the offset for the subrange
// and store into the ith place
vtkm::cont::ArrayHandleCounting<vtkm::Id> subsetIndexArray(1, 1, nActiveSupernodes-1);
if (nActiveSupernodes > 1) {
DegreeSubrangeOffset degreeSubrangeOffset;
vtkm::worklet::DispatcherMapField<DegreeSubrangeOffset>
degreeSubrangeOffsetDispatcher(degreeSubrangeOffset);
degreeSubrangeOffsetDispatcher.Invoke(subsetIndexArray, // input
sortVector, // input (whole array)
updegree); // output (whole array)
}
// 4. Compute the delta to get the degree.
if (nActiveSupernodes > 1) {
DegreeDelta degreeDelta(nActiveSupernodes);
vtkm::worklet::DispatcherMapField<DegreeDelta>
degreeDeltaDispatcher(degreeDelta);
degreeDeltaDispatcher.Invoke(subsetIndexArray, // input
sortVector, // input
updegree); // in out
}
// Now repeat the same steps for the downdegree
// 1. Copy the neighbours for each active edge
if (nActiveSupernodes > 0) {
CopyNeighbors copyNeighbors;
vtkm::worklet::DispatcherMapField<CopyNeighbors>
copyNeighborsDispatcher(copyNeighbors);
copyNeighborsDispatcher.Invoke(activeSupernodeIndexArray, // input
activeSupernodes, // input (whole array)
splitArcs, // input (whole array)
sortVector); // output
}
// 2. Sort the neighbours
DeviceAlgorithm::Sort(sortVector);
// 3. For each value, store the beginning & end of the range (in parallel)
// The 0th element is guaranteed to be NO_VERTEX_ASSIGNED, & can be skipped
// Otherwise, if the i-1th element is different, we are the offset for the subrange
// and store into the ith place
if (nActiveSupernodes > 1) {
DegreeSubrangeOffset degreeSubrangeOffset;
vtkm::worklet::DispatcherMapField<DegreeSubrangeOffset>
degreeSubrangeOffsetDispatcher(degreeSubrangeOffset);
degreeSubrangeOffsetDispatcher.Invoke(subsetIndexArray, // input
sortVector, // input (whole array)
downdegree); // output (whole array)
}
// 4. Compute the delta to get the degree.
if (nActiveSupernodes > 1) {
DegreeDelta degreeDelta(nActiveSupernodes);
vtkm::worklet::DispatcherMapField<DegreeDelta>
degreeDeltaDispatcher(degreeDelta);
degreeDeltaDispatcher.Invoke(subsetIndexArray, // input
sortVector, // input (whole array)
downdegree); // in out (whole array)
}
#ifdef DEBUG_PRINT
DebugPrint("Degrees Recomputed");
#endif
} // FindDegrees()
// small class for storing the contour arcs
class EdgePair
{
public:
vtkm::Id low, high;
// constructor - defaults to -1
EdgePair(vtkm::Id Low = -1, vtkm::Id High = -1) : low(Low), high(High) {}
};
// comparison operator <
bool operator < (const EdgePair LHS, const EdgePair RHS)
{
if (LHS.low < RHS.low) return true;
if (LHS.low > RHS.low) return false;
if (LHS.high < RHS.high) return true;
if (LHS.high > RHS.high) return false;
return false;
}
struct SaddlePeakSort
{
VTKM_EXEC_CONT bool operator()(const vtkm::Pair<vtkm::Id,vtkm::Id>& a,
const vtkm::Pair<vtkm::Id,vtkm::Id>& b) const
{
if (a.first < b.first) return true;
if (a.first > b.first) return false;
if (a.second < b.second) return true;
if (a.second > b.second) return false;
return false;
}
};
// sorted print routine
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::CollectSaddlePeak(
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > &saddlePeak)
{
// Collect the valid saddle peak pairs
std::vector<vtkm::Pair<vtkm::Id, vtkm::Id> > superarcVector;
for (vtkm::Id supernode = 0; supernode < supernodes.GetNumberOfValues(); supernode++)
{
// ID of regular node
vtkm::Id regularID = supernodes.GetPortalConstControl().Get(supernode);
// retrieve ID of target supernode
vtkm::Id superTo = superarcs.GetPortalConstControl().Get(supernode);
// if this is true, it is the last pruned vertex
if (superTo == NO_VERTEX_ASSIGNED)
continue;
// retrieve the regular ID for it
vtkm::Id regularTo = supernodes.GetPortalConstControl().Get(superTo);
// how we print depends on which end has lower ID
if (regularID < regularTo)
{ // from is lower
// extra test to catch duplicate edge
if (superarcs.GetPortalConstControl().Get(superTo) != supernode)
superarcVector.push_back(vtkm::make_Pair(regularID, regularTo));
} // from is lower
else
superarcVector.push_back(vtkm::make_Pair(regularTo, regularID));
} // per vertex
// Setting saddlePeak reference to the make_ArrayHandle directly does not work
vtkm::Id nSuperarcs = superarcVector.size();
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id,vtkm::Id> > tempArray = vtkm::cont::make_ArrayHandle(superarcVector);
// now sort it
DeviceAlgorithm::Sort(tempArray, SaddlePeakSort());
DeviceAlgorithm::Copy(tempArray, saddlePeak);
#ifdef DEBUG_PRINT
for (vtkm::Id superarc = 0; superarc < nSuperarcs; superarc++)
{
std::cout << setw(PRINT_WIDTH) << saddlePeak.GetPortalControl().Get(superarc).first << " ";
std::cout << setw(PRINT_WIDTH) << saddlePeak.GetPortalControl().Get(superarc).second << std::endl;
}
#endif
} // CollectSaddlePeak()
// debug routine
template <typename T, typename StorageType, typename DeviceAdapter>
void ContourTree<T,StorageType,DeviceAdapter>::DebugPrint(const char *message)
{
std::cout << "---------------------------" << std::endl;
std::cout << string(message) << std::endl;
std::cout << "---------------------------" << std::endl;
std::cout << std::endl;
// print out the supernode arrays
vtkm::Id nSupernodes = supernodes.GetNumberOfValues();
printHeader(nSupernodes);
printIndices("Supernodes", supernodes);
vtkm::cont::ArrayHandle<vtkm::Id> supervalues;
DeviceAlgorithm::Copy(PermuteValueType(supernodes, values), supervalues);
printValues("Value", supervalues);
printIndices("Up degree", updegree);
printIndices("Down degree", downdegree);
printIndices("Join arc", joinArcs);
printIndices("Split arc", splitArcs);
printIndices("Superarcs", superarcs);
std::cout << std::endl;
// print out the active supernodes
vtkm::Id nActiveSupernodes = activeSupernodes.GetNumberOfValues();
printHeader(nActiveSupernodes);
printIndices("Active Supernodes", activeSupernodes);
vtkm::cont::ArrayHandle<vtkm::Id> activeUpdegree;
DeviceAlgorithm::Copy(PermuteIndexType(activeSupernodes, updegree), activeUpdegree);
printIndices("Active Up Degree", activeUpdegree);
vtkm::cont::ArrayHandle<vtkm::Id> activeDowndegree;
DeviceAlgorithm::Copy(PermuteIndexType(activeSupernodes, downdegree), activeDowndegree);
printIndices("Active Down Degree", activeDowndegree);
vtkm::cont::ArrayHandle<vtkm::Id> activeJoinArcs;
DeviceAlgorithm::Copy(PermuteIndexType(activeSupernodes, joinArcs), activeJoinArcs);
printIndices("Active Join Arcs", activeJoinArcs);
vtkm::cont::ArrayHandle<vtkm::Id> activeSplitArcs;
DeviceAlgorithm::Copy(PermuteIndexType(activeSupernodes, splitArcs), activeSplitArcs);
printIndices("Active Split Arcs", activeSplitArcs);
vtkm::cont::ArrayHandle<vtkm::Id> activeSuperarcs;
DeviceAlgorithm::Copy(PermuteIndexType(activeSupernodes, superarcs), activeSuperarcs);
printIndices("Active Superarcs", activeSuperarcs);
std::cout << std::endl;
} // DebugPrint()
}
}
}
#endif

@ -0,0 +1,92 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// CopyJoinSplit.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_copy_join_split_h
#define vtkm_worklet_contourtree_copy_join_split_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class CopyJoinSplit : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // (input) index into super nodes
WholeArrayIn<IdType> inbound, // (input) join or split arcs
WholeArrayIn<IdType> indegree, // (input)
WholeArrayIn<IdType> outdegree, // (input)
WholeArrayOut<IdType> outbound); // (output) join or split arcs
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
CopyJoinSplit() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& superID,
const InFieldPortalType& inbound,
const InFieldPortalType& indegree,
const InFieldPortalType& outdegree,
const OutFieldPortalType& outbound) const
{
// if the vertex is critical, set it to -1
if ((outdegree.Get(superID) != 1) || (indegree.Get(superID) != 1))
outbound.Set(superID, NO_VERTEX_ASSIGNED);
// check the inbound neighbour
// if regular, set it to point outwards
vtkm::Id inNeighbour = inbound.Get(superID);
if (inNeighbour != NO_VERTEX_ASSIGNED)
{ // inbound exists
if ((outdegree.Get(inNeighbour) == 1) && (indegree.Get(inNeighbour) == 1))
outbound.Set(inNeighbour, superID);
} // inbound exists
}
}; // CopyJoinSplit
}
}
}
#endif

@ -0,0 +1,82 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// CopyNeighbors.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_copy_neighbors_h
#define vtkm_worklet_contourtree_copy_neighbors_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet
class CopyNeighbors : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> activeSupernode, // (input) index into supernodes
WholeArrayIn<IdType> activeSupernodes, // (input) active supernode vertex IDs
WholeArrayIn<IdType> arcs, // (input) merge tree arcs
FieldOut<IdType> sortVector); // (output) neighbors for active edge
typedef _4 ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
CopyNeighbors() {}
template <typename InFieldPortalType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id& activeSupernode,
const InFieldPortalType& activeSupernodes,
const InFieldPortalType& arcs) const
{
vtkm::Id sortVector;
vtkm::Id superID = activeSupernodes.Get(activeSupernode);
vtkm::Id neighbour = arcs.Get(superID);
sortVector = neighbour;
return sortVector;
}
}; // CopyNeighbors
}
}
}
#endif

@ -0,0 +1,95 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// CopySupernodes.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_copy_supernodes_h
#define vtkm_worklet_contourtree_copy_supernodes_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class CopySupernodes : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> isSupernode, // (input) is this a supernode
FieldIn<IdType> regularID, // (input) candidate ID
FieldIn<IdType> superID, // (input) supernode ID
FieldIn<IdType> upCandidate, // (input)
FieldIn<IdType> downCandidate, // (input)
WholeArrayOut<IdType> regularToCritical, // (output)
WholeArrayOut<IdType> supernodes, // (output) compacted supernodes
WholeArrayOut<IdType> updegree, // (output) compacted updegree
WholeArrayOut<IdType> downdegree); // (output) compacted downdegree
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8, _9);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
CopySupernodes() {}
template <typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& isSupernode,
const vtkm::Id& regularID,
const vtkm::Id& superID,
const vtkm::Id& upCandidate,
const vtkm::Id& downCandidate,
const OutFieldPortalType& regularToCritical,
const OutFieldPortalType& supernodes,
const OutFieldPortalType& updegree,
const OutFieldPortalType& downdegree) const
{
if (isSupernode)
{ // supernode
// update the inverse lookup, &c.
regularToCritical.Set(regularID, superID);
supernodes.Set(superID, regularID);
updegree.Set(superID, upCandidate);
downdegree.Set(superID, downCandidate);
}
}
}; // CopySupernodes
}
}
}
#endif

@ -0,0 +1,92 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// DegreeDelta.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_degree_delta_h
#define vtkm_worklet_contourtree_degree_delta_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class DegreeDelta : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> sortID, // (input) index into sorted vertices [1..N]
WholeArrayIn<IdType> sortVector, // (input) sorted vector of vertices
WholeArrayOut<IdType> candidate); // (output) candidate
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
vtkm::Id nCandidates;
// Constructor
VTKM_EXEC_CONT
DegreeDelta(vtkm::Id NCandidates) : nCandidates(NCandidates) {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& sortID,
const InFieldPortalType& sortVector,
const OutFieldPortalType& candidate) const
{
vtkm::Id iCandidate = sortVector.Get(sortID);
// last element needs to be subtracted from vector size
if (sortID == nCandidates-1)
{ // final element
candidate.Set(iCandidate, (nCandidates - candidate.Get(iCandidate)));
} // final element
// otherwise, if the next one is different
else
{ // not the last element
vtkm::Id nextCandidate = sortVector.Get(sortID+1);
if (iCandidate != nextCandidate)
{ // no match
candidate.Set(iCandidate, (sortID+1 - candidate.Get(iCandidate)));
} // no match
} // not the last element
}
}; // DegreeDelta
}
}
}
#endif

@ -0,0 +1,82 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// DegreeSubrangeOffset.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_degree_subrange_offset_h
#define vtkm_worklet_contourtree_degree_subrange_offset_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet
class DegreeSubrangeOffset : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> sortID, // (input) index into sort vector
WholeArrayIn<IdType> sortVector, // (input)
WholeArrayOut<IdType> degree); // (output)
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
DegreeSubrangeOffset() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& sortID,
const InFieldPortalType& sortVector,
const OutFieldPortalType& degree) const
{
vtkm::Id superID = sortVector.Get(sortID);
vtkm::Id prevSuper = sortVector.Get(sortID-1);
// if they don't match, we've found a boundary
if (superID != prevSuper)
degree.Set(superID, sortID);
}
}; // DegreeSubrangeOffset
}
}
}
#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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// EdgePeakComparator.h - a comparator for edges that sorts on four indices
//
//=======================================================================================
//
// COMMENTS:
//
// A comparator that sorts edges by:
// i. the chain maximum for the upper end of the edge
// this clusters all edges together that lead to the chain maximum
// ii. the index of the low end of the edge
// this sorts the edges for the chain max by the low end
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_edge_peak_comparator_h
#define vtkm_worklet_contourtree_edge_peak_comparator_h
namespace vtkm {
namespace worklet {
namespace contourtree {
// Comparator for edges to sort governing saddles high
template <typename T, typename StorageType, typename DeviceAdapter>
class EdgePeakComparator
{
public:
typedef typename vtkm::cont::ArrayHandle<T,StorageType>::template ExecutionTypes<DeviceAdapter>::PortalConst ValuePortalType;
typedef typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
ValuePortalType values;
IdPortalType valueIndex;
IdPortalType edgeFar;
IdPortalType edgeNear;
IdPortalType arcArray;
bool isJoinGraph;
VTKM_CONT
EdgePeakComparator(ValuePortalType Values,
IdPortalType ValueIndex,
IdPortalType EdgeFar,
IdPortalType EdgeNear,
IdPortalType ArcArray,
bool IsJoinGraph) :
values(Values),
valueIndex(ValueIndex),
edgeFar(EdgeFar),
edgeNear(EdgeNear),
arcArray(ArcArray),
isJoinGraph(IsJoinGraph) {}
VTKM_EXEC
bool operator() (const vtkm::Id &i, const vtkm::Id &j) const
{
// first compare the far end
if (edgeFar.Get(i) < edgeFar.Get(j))
return true ^ isJoinGraph;
if (edgeFar.Get(j) < edgeFar.Get(i))
return false ^ isJoinGraph;
// the compare the values of the low end
vtkm::Id valueIndex1 = valueIndex.Get(edgeNear.Get(i));
vtkm::Id valueIndex2 = valueIndex.Get(edgeNear.Get(j));
if (values.Get(valueIndex1) < values.Get(valueIndex2))
return true ^ isJoinGraph;
if (values.Get(valueIndex2) < values.Get(valueIndex1))
return false ^ isJoinGraph;
// finally compare the indices
if (valueIndex1 < valueIndex2)
return true ^ isJoinGraph;
if (valueIndex2 < valueIndex1)
return false ^ isJoinGraph;
if (i < j)
return false ^ isJoinGraph;
if (j < i)
return true ^ isJoinGraph;
// fallback can happen when multiple paths end at same extremum
return false; //true ^ graph.isJoinGraph;
}
}; // EdgePeakComparator
}
}
}
#endif

@ -0,0 +1,74 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// FillSupernodes.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_fill_supernodes_h
#define vtkm_worklet_contourtree_fill_supernodes_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet
class FillSupernodes : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> upCandidate, // (input)
FieldIn<IdType> downCandidate, // (input)
FieldOut<IdType> isSupernode); // (output)
typedef _3 ExecutionSignature(_1, _2);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
FillSupernodes() {}
vtkm::Id operator()(const vtkm::Id& upCandidate,
const vtkm::Id& downCandidate) const
{
vtkm::Id isSupernode = ((upCandidate != 1) || (downCandidate != 1));
return isSupernode;
}
}; // FillSupernodes
}
}
}
#endif

@ -0,0 +1,95 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// FindLeaves.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_find_leaves_h
#define vtkm_worklet_contourtree_find_leaves_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class FindLeaves : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // (input) super nodes
WholeArrayIn<IdType> updegree, // (input)
WholeArrayIn<IdType> downdegree, // (input)
WholeArrayIn<IdType> joinArc, // (input)
WholeArrayIn<IdType> splitArc, // (input)
WholeArrayInOut<IdType> superarc); // (i/o)
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
FindLeaves() {}
template <typename InPortalFieldType, typename OutPortalFieldType>
VTKM_EXEC
void operator()(const vtkm::Id& superID,
const InPortalFieldType& updegree,
const InPortalFieldType& downdegree,
const InPortalFieldType& joinArc,
const InPortalFieldType& splitArc,
const OutPortalFieldType& superarc) const
{
// omit previously processed vertices
if (superarc.Get(superID) != NO_VERTEX_ASSIGNED)
return;
// Test for extremality - maxima first
if ((updegree.Get(superID) == 0) && (downdegree.Get(superID) == 1))
{ // maximum
superarc.Set(superID, joinArc.Get(superID));
} // maximum
// minima next
else if ((updegree.Get(superID) == 1) && (downdegree.Get(superID) == 0))
{ // minimum
superarc.Set(superID, splitArc.Get(superID));
} // minimum
}
}; // FindLeaves
}
}
}
#endif

@ -0,0 +1,120 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// GoverningSaddleFinder.h - iterator for finding governing saddle
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_governing_saddle_finder_h
#define vtkm_worklet_contourtree_governing_saddle_finder_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class GoverningSaddleFinder : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> edgeNo, // (input) index into sorted edges
WholeArrayIn<IdType> edgeSorter, // (input) sorted edge index
WholeArrayIn<IdType> edgeFar, // (input) high ends of edges
WholeArrayIn<IdType> edgeNear, // (input) low ends of edges
WholeArrayOut<IdType> prunesTo, // (output) where vertex is pruned to
WholeArrayOut<IdType> outdegree); // (output) updegree of vertex
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
GoverningSaddleFinder() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id &edgeNo,
const InFieldPortalType &edgeSorter,
const InFieldPortalType &edgeFar,
const InFieldPortalType &edgeNear,
const OutFieldPortalType &prunesTo,
const OutFieldPortalType &outdegree) const
{
// default to true
bool isBestSaddleEdge = true;
// retrieve the edge ID
vtkm::Id edge = edgeSorter.Get(edgeNo);
// edge no. 0 is always best, so skip it
if (edgeNo != 0)
{
// retrieve the previous edge
vtkm::Id prevEdge = edgeSorter.Get(edgeNo-1);
// if the previous edge has the same far end
if (edgeFar.Get(prevEdge) == edgeFar.Get(edge))
isBestSaddleEdge = false;
}
if (isBestSaddleEdge)
{ // found an extremum
// retrieve the near end as the saddle
vtkm::Id saddle = edgeNear.Get(edge);
// and the far end as the extremum
vtkm::Id extreme = edgeFar.Get(edge);
// set the extremum to point to the saddle in the chainExtremum array
prunesTo.Set(extreme, saddle);
// and set the outdegree to 0
outdegree.Set(extreme, 0);
} // found a extremum
} // operator()
}; // GoverningSaddleFinder
}
}
}
#endif

@ -0,0 +1,101 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// JoinArcConnector.h - functor that sets the final join arc connections
//
//=======================================================================================
//
// COMMENTS:
//
// This functor checks the vertex next lowest in the sort order. If it shares a maximum,
// we connect to it, otherwise we connect to the maximum's saddle.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_join_arc_connector_h
#define vtkm_worklet_contourtree_join_arc_connector_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class JoinArcConnector : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into sorted edges
WholeArrayIn<IdType> vertexSorter, // (input) sorting indices
WholeArrayIn<IdType> extrema, // (input) maxima
WholeArrayIn<IdType> saddles, // (input) saddles
WholeArrayOut<IdType> mergeArcs); // (output) target for write back
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
JoinArcConnector() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const InFieldPortalType& vertexSorter,
const InFieldPortalType& extrema,
const InFieldPortalType& saddles,
const OutFieldPortalType& mergeArcs) const
{
// work out whether we have the low element on the join arc
bool joinToSaddle = false;
if (vertex == 0) {
joinToSaddle = true;
} else {
joinToSaddle = (extrema.Get(vertexSorter.Get(vertex)) != extrema.Get(vertexSorter.Get(vertex-1)));
}
// now set the join arcs for everybody
if (joinToSaddle)
mergeArcs.Set(vertexSorter.Get(vertex), saddles.Get(vertexSorter.Get(vertex)));
else
mergeArcs.Set(vertexSorter.Get(vertex), vertexSorter.Get(vertex - 1));
}
}; // JoinArcConnector
}
}
}
#endif

@ -0,0 +1,126 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// JoinSuperArcFinder.h - functor that searches through the superarcs to assign each vertex
//
//=======================================================================================
//
// COMMENTS:
//
// After the core join tree is constructed, we need to assign each vertex to a join superarc
// This was previously done with a set of rocking iterations, which burned extra memory and
// work. The OpenMP version was therefore updated so that each vertex looped until it found
// it's destination arc.
//
// This functor implements that for use by a for_each call.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_join_super_arc_finder_h
#define vtkm_worklet_contourtree_join_super_arc_finder_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include "vtkm/worklet/contourtree/Types.h"
#include "vtkm/worklet/contourtree/VertexValueComparator.h"
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for finding join superarc - expressed as a unary functor since it is not
// guaranteed to write back
// There will be no out-of-sequence writes, since:
// 1. Critical points are already set and are simply skipped
// 2. Regular points only read from critical points
// 3. Regular points only write to critical points
//
template <typename T>
class JoinSuperArcFinder : public vtkm::worklet::WorkletMapField
{
public:
struct TagType : vtkm::ListTagBase<T> {};
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into sorted edges
WholeArrayIn<TagType> values, // (input) data values
WholeArrayInOut<IdType> saddles, // (in out) saddles
WholeArrayInOut<IdType> extrema); // (in out) maxima
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef _1 InputDomain;
bool isJoinTree;
// Constructor
VTKM_EXEC_CONT
JoinSuperArcFinder(bool IsJoinTree) : isJoinTree(IsJoinTree) {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const InFieldPortalType& values,
const OutFieldPortalType& saddles,
const OutFieldPortalType& extrema) const
{
VertexValueComparator<InFieldPortalType> lessThan(values);
// local copies
vtkm::Id saddle = saddles.Get(vertex);
vtkm::Id extreme = extrema.Get(vertex);
// now test for regular points
if (saddle != extreme)
return;
// while loop
while (lessThan(saddle, vertex, isJoinTree))
{ // saddle above vertex
extreme = extrema.Get(saddle);
saddle = saddles.Get(saddle);
// if we're in the trunk, break immediately
if (saddle == NO_VERTEX_ASSIGNED)
break;
} // saddle above vertex
// when done, write back to the array
extrema.Set(vertex, extreme);
saddles.Set(vertex, saddle);
}
}; // JoinSuperArcFinder
}
}
}
#endif

@ -0,0 +1,100 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// JoinTreeTransferrer.h - functor that sets new active edges per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor identifies for each vertex which edges to keep. For arbitrary meshes,
// this should use reductions. For regular meshes, this way is faster due to low bounded
// updegree.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_join_tree_transferrer_h
#define vtkm_worklet_contourtree_join_tree_transferrer_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class JoinTreeTransferrer : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into active vertices
FieldIn<IdType> prunesTo, // (input) where vertex is pruned to
WholeArrayIn<IdType> valueIndex, // (input) indices into main array
WholeArrayIn<IdType> chainExtemum, // (input) chain extemum for vertices
WholeArrayOut<IdType> saddles, // (output) saddle array for writing
WholeArrayOut<IdType> arcArray); // (output) arc / max array for writing
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
JoinTreeTransferrer() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const vtkm::Id& prunesTo,
const InFieldPortalType& valueIndex,
const InFieldPortalType& chainExtremum,
const OutFieldPortalType& saddles,
const OutFieldPortalType& arcArray) const
{
// convert vertex & prunesTo to indices in original data
// and write to saddle array
if (prunesTo == NO_VERTEX_ASSIGNED)
saddles.Set(valueIndex.Get(vertex), NO_VERTEX_ASSIGNED);
else
saddles.Set(valueIndex.Get(vertex), valueIndex.Get(prunesTo));
// and in either event, we need to transfer the chain maximum
arcArray.Set(valueIndex.Get(vertex), valueIndex.Get(chainExtremum.Get(vertex)));
}
}; // JoinTreeTransferrer
}
}
}
#endif

@ -0,0 +1,44 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtkm_worklet_contourtree_link_component_case_table_2d_h
#define vtkm_worklet_contourtree_link_component_case_table_2d_h
#include <vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation_Macros.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
const vtkm::IdComponent neighbourOffsets[N_INCIDENT_EDGES][2] = {
{ 0, 1 }, { 1, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { -1, 0 }
};
const vtkm::UInt8 linkComponentCaseTable[64] = {
0, 1, 2, 2, 4, 5, 4, 4, 8, 9, 10, 10, 8, 9, 8, 8, 16, 17, 18, 18, 20, 21, 20, 20, 16,
17, 18, 18, 16, 17, 16, 16, 32, 32, 34, 32, 36, 36, 36, 32, 40, 40, 42, 40, 40, 40, 40, 32, 32, 32,
34, 32, 36, 36, 36, 32, 32, 32, 34, 32, 32, 32, 32, 32
};
}
}
}
#endif

@ -0,0 +1,700 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtkm_worklet_contourtree_link_component_case_table_3d_h
#define vtkm_worklet_contourtree_link_component_case_table_3d_h
#include <vtkm/Types.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_Triangulation_Macros.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
/*
const vtkm::IdComponent neighbourOffsets3D[N_INCIDENT_EDGES_3D][3] = {
{ -1, -1, -1 }, { 0, -1, 0 }, { -1, -1, 0 }, { -1, 0, 0 }, { -1, 0, -1 }, { 0, 0, -1 }, { 0, -1, -1 },
{ 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 }
};
*/
const vtkm::UInt16 linkComponentCaseTable3D[16384] = {
0, 1, 2, 2, 4, 4, 4, 4, 8, 8, 10, 8, 8, 8, 8, 8, 16, 16, 18, 16, 20, 16, 20, 16, 16,
16, 18, 16, 16, 16, 16, 16, 32, 32, 34, 32, 36, 32, 36, 32, 40, 32, 42, 32, 40, 32, 40, 32, 32, 32,
34, 32, 36, 32, 36, 32, 32, 32, 34, 32, 32, 32, 32, 32, 64, 64, 64, 64, 68, 64, 64, 64, 72, 64, 72,
64, 72, 64, 64, 64, 80, 64, 80, 64, 84, 64, 80, 64, 80, 64, 80, 64, 80, 64, 64, 64, 64, 64, 64, 64,
68, 64, 64, 64, 72, 64, 72, 64, 72, 64, 64, 64, 64, 64, 64, 64, 68, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 128, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 144, 144, 144, 128, 144, 128,
144, 128, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 128, 160, 128, 160, 128, 160, 128, 160, 128, 160, 128, 160,
128, 160, 160, 160, 128, 160, 128, 160, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 192, 128, 128, 192, 128, 128, 128,
192, 128, 128, 128, 192, 128, 128, 128, 208, 192, 144, 128, 208, 128, 144, 128, 192, 128, 128, 128, 192, 128, 128, 128, 192,
192, 128, 128, 192, 128, 128, 128, 192, 128, 128, 128, 192, 128, 128, 128, 192, 192, 128, 128, 192, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 256, 257, 258, 258, 260, 260, 260, 260, 256, 256, 258, 256, 256, 256, 256, 256, 256, 256, 258,
256, 260, 256, 260, 256, 256, 256, 258, 256, 256, 256, 256, 256, 256, 256, 258, 256, 260, 256, 260, 256, 256, 256, 258, 256,
256, 256, 256, 256, 256, 256, 258, 256, 260, 256, 260, 256, 256, 256, 258, 256, 256, 256, 256, 256, 320, 320, 320, 320, 324,
320, 320, 320, 320, 256, 320, 256, 320, 256, 256, 256, 320, 256, 320, 256, 324, 256, 320, 256, 320, 256, 320, 256, 320, 256,
256, 256, 256, 256, 256, 256, 260, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 260, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 384, 385, 384, 384, 384, 384, 384, 384, 256, 256, 256, 256, 256, 256, 256, 256,
384, 384, 384, 256, 384, 256, 384, 256, 256, 256, 256, 256, 256, 256, 256, 256, 384, 384, 384, 256, 384, 256, 384, 256, 256,
256, 256, 256, 256, 256, 256, 256, 384, 384, 384, 256, 384, 256, 384, 256, 256, 256, 256, 256, 256, 256, 256, 256, 448, 448,
384, 384, 448, 384, 384, 384, 320, 256, 256, 256, 320, 256, 256, 256, 448, 384, 384, 256, 448, 256, 384, 256, 320, 256, 256,
256, 320, 256, 256, 256, 384, 384, 256, 256, 384, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 384, 384, 256, 256,
384, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 512, 513, 514, 514, 516, 516, 516, 516, 512, 512, 514, 512, 512,
512, 512, 512, 528, 528, 530, 528, 532, 528, 532, 528, 512, 512, 514, 512, 512, 512, 512, 512, 544, 544, 546, 544, 548, 544,
548, 544, 544, 512, 546, 512, 544, 512, 544, 512, 544, 544, 546, 544, 548, 544, 548, 544, 512, 512, 514, 512, 512, 512, 512,
512, 576, 576, 576, 576, 580, 576, 576, 576, 576, 512, 576, 512, 576, 512, 512, 512, 592, 576, 592, 576, 596, 576, 592, 576,
576, 512, 576, 512, 576, 512, 512, 512, 576, 576, 576, 576, 580, 576, 576, 576, 576, 512, 576, 512, 576, 512, 512, 512, 576,
576, 576, 576, 580, 576, 576, 576, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 512, 512, 512, 512, 512, 512, 512, 512,
512, 512, 512, 512, 512, 512, 528, 528, 528, 512, 528, 512, 528, 512, 512, 512, 512, 512, 512, 512, 512, 512, 544, 544, 544,
512, 544, 512, 544, 512, 544, 512, 544, 512, 544, 512, 544, 512, 544, 544, 544, 512, 544, 512, 544, 512, 512, 512, 512, 512,
512, 512, 512, 512, 576, 576, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 592, 576, 528, 512, 592,
512, 528, 512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 576, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 512,
512, 512, 576, 576, 512, 512, 576, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 514, 514, 516, 516, 516,
516, 512, 512, 514, 512, 512, 512, 512, 512, 512, 512, 514, 512, 516, 512, 516, 512, 512, 512, 514, 512, 512, 512, 512, 512,
512, 512, 514, 512, 516, 512, 516, 512, 512, 512, 514, 512, 512, 512, 512, 512, 512, 512, 514, 512, 516, 512, 516, 512, 512,
512, 514, 512, 512, 512, 512, 512, 576, 576, 576, 576, 580, 576, 576, 576, 576, 512, 576, 512, 576, 512, 512, 512, 576, 512,
576, 512, 580, 512, 576, 512, 576, 512, 576, 512, 576, 512, 512, 512, 512, 512, 512, 512, 516, 512, 512, 512, 512, 512, 512,
512, 512, 512, 512, 512, 512, 512, 512, 512, 516, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 512, 512,
512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512,
512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512,
512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 576, 576, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 512, 512,
512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 576, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512,
512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 1024,
1025, 1024, 1024, 1028, 1028, 1024, 1024, 1032, 1032, 1032, 1024, 1032, 1032, 1024, 1024, 1040, 1040, 1040, 1024, 1044, 1040, 1040, 1024, 1040, 1040,
1040, 1024, 1040, 1040, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1032, 1024, 1032, 1024, 1032, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1032, 1024, 1032, 1024,
1032, 1024, 1024, 1024, 1040, 1024, 1040, 1024, 1044, 1024, 1040, 1024, 1040, 1024, 1040, 1024, 1040, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028,
1024, 1024, 1024, 1032, 1024, 1032, 1024, 1032, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1152, 1153, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1152, 1024, 1024, 1168, 1168, 1040, 1024, 1168, 1152, 1040,
1024, 1152, 1152, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1152, 1024, 1024, 1024, 1152, 1024, 1024, 1024,
1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1152,
1024, 1024, 1024, 1152, 1024, 1024, 1024, 1168, 1152, 1040, 1024, 1168, 1024, 1040, 1024, 1152, 1024, 1024, 1024, 1152, 1024, 1024, 1024, 1152, 1152,
1024, 1024, 1152, 1024, 1024, 1024, 1152, 1024, 1024, 1024, 1152, 1024, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1280, 1281, 1280, 1280, 1284, 1284, 1280, 1280, 1280, 1280, 1280, 1024, 1280, 1280, 1024, 1024, 1280, 1280, 1280, 1024,
1284, 1280, 1280, 1024, 1280, 1280, 1280, 1024, 1280, 1280, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1280, 1280, 1280, 1280, 1284, 1280,
1280, 1280, 1280, 1024, 1280, 1024, 1280, 1024, 1024, 1024, 1280, 1024, 1280, 1024, 1284, 1024, 1280, 1024, 1280, 1024, 1280, 1024, 1280, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1408, 1409, 1280, 1280, 1408, 1408, 1280, 1280, 1280, 1280, 1024, 1024, 1280, 1280, 1024, 1024, 1408,
1408, 1280, 1024, 1408, 1280, 1280, 1024, 1280, 1280, 1024, 1024, 1280, 1280, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1408, 1408, 1280,
1280, 1408, 1280, 1280, 1280, 1280, 1024, 1024, 1024, 1280, 1024, 1024, 1024, 1408, 1152, 1280, 1024, 1408, 1024, 1280, 1024, 1280, 1024, 1024, 1024,
1280, 1024, 1024, 1024, 1152, 1152, 1024, 1024, 1152, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1152, 1152, 1024, 1024, 1152,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1536, 1537, 1536, 1536, 1540, 1540, 1536, 1536, 1536, 1536, 1536, 1024, 1536, 1536,
1024, 1024, 1552, 1552, 1552, 1536, 1556, 1552, 1552, 1536, 1536, 1536, 1536, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1536, 1536, 1540, 1536, 1536,
1536, 1536, 1024, 1536, 1024, 1536, 1024, 1024, 1024, 1536, 1536, 1536, 1536, 1540, 1536, 1536, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1536, 1536, 1536, 1536, 1540, 1536, 1536, 1536, 1536, 1024, 1536, 1024, 1536, 1024, 1024, 1024, 1552, 1536, 1552, 1536, 1556, 1536, 1552, 1536, 1536,
1024, 1536, 1024, 1536, 1024, 1024, 1024, 1536, 1536, 1536, 1536, 1540, 1536, 1536, 1536, 1536, 1024, 1536, 1024, 1536, 1024, 1024, 1024, 1536, 1536,
1536, 1536, 1540, 1536, 1536, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1536, 1537, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024,
1024, 1536, 1536, 1024, 1024, 1552, 1552, 1040, 1024, 1552, 1536, 1040, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024,
1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1552, 1536, 1040, 1024, 1552, 1024,
1040, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024,
1024, 1536, 1536, 1024, 1024, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1536, 1537, 1536, 1536, 1540, 1540, 1536, 1536,
1536, 1536, 1536, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1536, 1024, 1540, 1536, 1536, 1024, 1536, 1536, 1536, 1024, 1536, 1536, 1024, 1024, 1024,
1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1536, 1536, 1536, 1536, 1540, 1536, 1536, 1536, 1536, 1024, 1536, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1536,
1024, 1540, 1024, 1536, 1024, 1536, 1024, 1536, 1024, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1028, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1536, 1537, 1024, 1024, 1536,
1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1536,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1536, 1536, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024,
1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1536, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 2048, 2049,
2048, 2048, 2052, 2052, 2048, 2048, 2056, 2056, 2056, 2048, 2056, 2056, 2048, 2048, 2064, 2064, 2064, 2048, 2068, 2064, 2064, 2048, 2064, 2064, 2064,
2048, 2064, 2064, 2048, 2048, 2080, 2080, 2080, 2048, 2084, 2080, 2080, 2048, 2088, 2080, 2088, 2048, 2088, 2080, 2080, 2048, 2080, 2080, 2080, 2048,
2084, 2080, 2080, 2048, 2080, 2080, 2080, 2048, 2080, 2080, 2048, 2048, 2112, 2112, 2048, 2048, 2116, 2112, 2048, 2048, 2120, 2112, 2056, 2048, 2120,
2112, 2048, 2048, 2128, 2112, 2064, 2048, 2132, 2112, 2064, 2048, 2128, 2112, 2064, 2048, 2128, 2112, 2048, 2048, 2112, 2112, 2048, 2048, 2116, 2112,
2048, 2048, 2120, 2112, 2056, 2048, 2120, 2112, 2048, 2048, 2112, 2112, 2048, 2048, 2116, 2112, 2048, 2048, 2112, 2112, 2048, 2048, 2112, 2112, 2048,
2048, 2048, 2049, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2064, 2064, 2064, 2048, 2064, 2048, 2064, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2080, 2080, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080,
2080, 2080, 2048, 2080, 2048, 2080, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048,
2048, 2048, 2112, 2048, 2048, 2048, 2128, 2112, 2064, 2048, 2128, 2048, 2064, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2112, 2048,
2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2304, 2305, 2304, 2304, 2308, 2308, 2304, 2304, 2304, 2304, 2304, 2048, 2304, 2304, 2048, 2048, 2304, 2304, 2304, 2048, 2308,
2304, 2304, 2048, 2304, 2304, 2304, 2048, 2304, 2304, 2048, 2048, 2304, 2304, 2304, 2048, 2308, 2304, 2304, 2048, 2304, 2304, 2304, 2048, 2304, 2304,
2048, 2048, 2304, 2304, 2304, 2048, 2308, 2304, 2304, 2048, 2304, 2304, 2304, 2048, 2304, 2304, 2048, 2048, 2368, 2368, 2304, 2304, 2372, 2368, 2304,
2304, 2368, 2304, 2304, 2048, 2368, 2304, 2048, 2048, 2368, 2304, 2304, 2048, 2372, 2304, 2304, 2048, 2368, 2304, 2304, 2048, 2368, 2304, 2048, 2048,
2304, 2304, 2048, 2048, 2308, 2304, 2048, 2048, 2304, 2304, 2048, 2048, 2304, 2304, 2048, 2048, 2304, 2304, 2048, 2048, 2308, 2304, 2048, 2048, 2304,
2304, 2048, 2048, 2304, 2304, 2048, 2048, 2304, 2305, 2304, 2304, 2304, 2304, 2304, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304,
2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304, 2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2304, 2304, 2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2368, 2368, 2304, 2304,
2368, 2304, 2304, 2304, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2368, 2304, 2304, 2048, 2368, 2048, 2304, 2048, 2112, 2048, 2048, 2048, 2112,
2048, 2048, 2048, 2304, 2304, 2048, 2048, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304, 2048, 2048, 2304, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2560, 2561, 2560, 2560, 2564, 2564, 2560, 2560, 2560, 2560, 2560, 2048, 2560, 2560, 2048,
2048, 2576, 2576, 2576, 2560, 2580, 2576, 2576, 2560, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2592, 2592, 2592, 2560, 2596, 2592, 2592, 2560,
2592, 2560, 2592, 2048, 2592, 2560, 2080, 2048, 2592, 2592, 2592, 2560, 2596, 2592, 2592, 2560, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2624,
2624, 2560, 2560, 2628, 2624, 2560, 2560, 2624, 2560, 2560, 2048, 2624, 2560, 2048, 2048, 2640, 2624, 2576, 2560, 2644, 2624, 2576, 2560, 2624, 2560,
2560, 2048, 2624, 2560, 2048, 2048, 2624, 2624, 2560, 2560, 2628, 2624, 2560, 2560, 2624, 2560, 2560, 2048, 2624, 2560, 2048, 2048, 2624, 2624, 2560,
2560, 2628, 2624, 2560, 2560, 2560, 2560, 2048, 2048, 2560, 2560, 2048, 2048, 2048, 2049, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2064, 2064, 2064, 2048, 2064, 2048, 2064, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2080, 2080, 2080, 2048, 2080,
2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2048, 2080, 2080, 2080, 2048, 2080, 2048, 2080, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2128, 2112, 2064, 2048, 2128, 2048, 2064,
2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048,
2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2560, 2561, 2560, 2560, 2564, 2564, 2560, 2560, 2560,
2560, 2560, 2048, 2560, 2560, 2048, 2048, 2560, 2560, 2560, 2048, 2564, 2560, 2560, 2048, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2560, 2560,
2560, 2048, 2564, 2560, 2560, 2048, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2560, 2560, 2560, 2048, 2564, 2560, 2560, 2048, 2560, 2560, 2560,
2048, 2560, 2560, 2048, 2048, 2624, 2624, 2560, 2560, 2628, 2624, 2560, 2560, 2624, 2560, 2560, 2048, 2624, 2560, 2048, 2048, 2624, 2560, 2560, 2048,
2628, 2560, 2560, 2048, 2624, 2560, 2560, 2048, 2624, 2560, 2048, 2048, 2560, 2560, 2048, 2048, 2564, 2560, 2048, 2048, 2560, 2560, 2048, 2048, 2560,
2560, 2048, 2048, 2560, 2560, 2048, 2048, 2564, 2560, 2048, 2048, 2560, 2560, 2048, 2048, 2560, 2560, 2048, 2048, 2048, 2049, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2112, 2112, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112,
2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2112, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2049, 2048,
2048, 2052, 2052, 2048, 2048, 2056, 2056, 2056, 2048, 2056, 2056, 2048, 2048, 2064, 2064, 2064, 2048, 2068, 2064, 2064, 2048, 2064, 2064, 2064, 2048,
2064, 2064, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2056, 2048, 2056, 2048, 2056, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2056, 2048, 2056, 2048, 2056, 2048,
2048, 2048, 2064, 2048, 2064, 2048, 2068, 2048, 2064, 2048, 2064, 2048, 2064, 2048, 2064, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048,
2048, 2056, 2048, 2056, 2048, 2056, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2049, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2064, 2064, 2064, 2048, 2064, 2048, 2064, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2064, 2048, 2064, 2048, 2064, 2048, 2064, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2304, 2305, 2304, 2304, 2308, 2308, 2304, 2304, 2304, 2304, 2304, 2048, 2304, 2304, 2048, 2048, 2304, 2304, 2304, 2048, 2308, 2304,
2304, 2048, 2304, 2304, 2304, 2048, 2304, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304, 2304, 2304, 2308, 2304, 2304, 2304,
2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2304, 2048, 2304, 2048, 2308, 2048, 2304, 2048, 2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2304, 2305, 2304, 2304, 2304, 2304, 2304, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304, 2304,
2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2304, 2304, 2304, 2304,
2304, 2304, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2304, 2048, 2304, 2048, 2304, 2048, 2304, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2560, 2561, 2560, 2560, 2564, 2564, 2560, 2560, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048,
2576, 2576, 2576, 2560, 2580, 2576, 2576, 2560, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2560, 2560, 2560, 2560, 2564, 2560, 2560, 2560, 2560,
2048, 2560, 2048, 2560, 2048, 2048, 2048, 2560, 2560, 2560, 2560, 2564, 2560, 2560, 2560, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2560, 2560,
2560, 2560, 2564, 2560, 2560, 2560, 2560, 2048, 2560, 2048, 2560, 2048, 2048, 2048, 2576, 2560, 2576, 2560, 2580, 2560, 2576, 2560, 2560, 2048, 2560,
2048, 2560, 2048, 2048, 2048, 2560, 2560, 2560, 2560, 2564, 2560, 2560, 2560, 2560, 2048, 2560, 2048, 2560, 2048, 2048, 2048, 2560, 2560, 2560, 2560,
2564, 2560, 2560, 2560, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2049, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2064, 2064, 2064, 2048, 2064, 2048, 2064, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2064, 2048, 2064, 2048, 2064, 2048, 2064, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2560, 2561, 2560, 2560, 2564, 2564, 2560, 2560, 2560, 2560,
2560, 2048, 2560, 2560, 2048, 2048, 2560, 2560, 2560, 2048, 2564, 2560, 2560, 2048, 2560, 2560, 2560, 2048, 2560, 2560, 2048, 2048, 2048, 2048, 2048,
2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2560, 2560, 2560, 2560, 2564, 2560, 2560, 2560, 2560, 2048, 2560, 2048, 2560, 2048, 2048, 2048, 2560, 2048, 2560, 2048, 2564,
2048, 2560, 2048, 2560, 2048, 2560, 2048, 2560, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2052, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2049, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 4096, 4097, 4098, 4098,
4100, 4100, 4100, 4100, 4104, 4104, 4106, 4104, 4104, 4104, 4104, 4104, 4112, 4112, 4114, 4112, 4116, 4112, 4116, 4112, 4112, 4112, 4114, 4112, 4112,
4112, 4112, 4112, 4096, 4096, 4098, 4096, 4100, 4096, 4100, 4096, 4104, 4096, 4106, 4096, 4104, 4096, 4104, 4096, 4096, 4096, 4098, 4096, 4100, 4096,
4100, 4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4160, 4160, 4160, 4160, 4164, 4160, 4160, 4160, 4168, 4160, 4168, 4160, 4168, 4160, 4160,
4160, 4176, 4160, 4176, 4160, 4180, 4160, 4176, 4160, 4176, 4160, 4176, 4160, 4176, 4160, 4160, 4160, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096,
4104, 4096, 4104, 4096, 4104, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224,
4225, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4240, 4240, 4240, 4224, 4240, 4224, 4240, 4224, 4224, 4224,
4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4224, 4096, 4224, 4096, 4224, 4096, 4224, 4096, 4224, 4096, 4224, 4096, 4224, 4096, 4224, 4224, 4224,
4096, 4224, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4288, 4288, 4224, 4224, 4288, 4224, 4224, 4224, 4288, 4224, 4224, 4224,
4288, 4224, 4224, 4224, 4304, 4288, 4240, 4224, 4304, 4224, 4240, 4224, 4288, 4224, 4224, 4224, 4288, 4224, 4224, 4224, 4224, 4224, 4096, 4096, 4224,
4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4097, 4098, 4098, 4100, 4100, 4100, 4100, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4098, 4096, 4100, 4096, 4100,
4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4098, 4096, 4100, 4096, 4100, 4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4098, 4096, 4100, 4096, 4100, 4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4160, 4160, 4160, 4160, 4164, 4160, 4160, 4160, 4160,
4096, 4160, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4160, 4096, 4164, 4096, 4160, 4096, 4160, 4096, 4160, 4096, 4160, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4224, 4225, 4224, 4224, 4224, 4224, 4224, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4224, 4096,
4224, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4224, 4096, 4224, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4224, 4224, 4224, 4096, 4224, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4288, 4288, 4224, 4224, 4288, 4224,
4224, 4224, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4288, 4224, 4224, 4096, 4288, 4096, 4224, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096,
4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4609, 4610, 4610, 4612, 4612, 4612, 4612, 4608, 4608, 4610, 4608, 4608, 4608, 4608, 4608, 4624,
4624, 4626, 4624, 4628, 4624, 4628, 4624, 4608, 4608, 4610, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4610, 4608, 4612, 4608, 4612, 4608, 4608, 4096,
4610, 4096, 4608, 4096, 4608, 4096, 4608, 4608, 4610, 4608, 4612, 4608, 4612, 4608, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4672, 4672, 4672,
4672, 4676, 4672, 4672, 4672, 4672, 4608, 4672, 4608, 4672, 4608, 4608, 4608, 4688, 4672, 4688, 4672, 4692, 4672, 4688, 4672, 4672, 4608, 4672, 4608,
4672, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612,
4608, 4608, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4609, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608,
4608, 4608, 4624, 4624, 4624, 4608, 4624, 4608, 4624, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608,
4096, 4608, 4096, 4608, 4096, 4608, 4096, 4608, 4096, 4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4672, 4672, 4608, 4608, 4672, 4608, 4608, 4608, 4672, 4608, 4608, 4608, 4672, 4608, 4608, 4608, 4688, 4672, 4624, 4608, 4688, 4608, 4624, 4608, 4672,
4608, 4608, 4608, 4672, 4608, 4608, 4608, 4608, 4608, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4608,
4096, 4096, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4098, 4098, 4100, 4100, 4100, 4100, 4096, 4096, 4098,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4098, 4096, 4100, 4096, 4100, 4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4098, 4096,
4100, 4096, 4100, 4096, 4096, 4096, 4098, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4098, 4096, 4100, 4096, 4100, 4096, 4096, 4096, 4098, 4096, 4096,
4096, 4096, 4096, 4160, 4160, 4160, 4160, 4164, 4160, 4160, 4160, 4160, 4096, 4160, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4160, 4096, 4164, 4096,
4160, 4096, 4160, 4096, 4160, 4096, 4160, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4160, 4160, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096,
4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4100,
4100, 4096, 4096, 4104, 4104, 4104, 4096, 4104, 4104, 4096, 4096, 4112, 4112, 4112, 4096, 4116, 4112, 4112, 4096, 4112, 4112, 4112, 4096, 4112, 4112,
4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104, 4096, 4104, 4096, 4104, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104, 4096, 4104, 4096, 4104, 4096, 4096, 4096,
4112, 4096, 4112, 4096, 4116, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104,
4096, 4104, 4096, 4104, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4225,
4096, 4096, 4224, 4224, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4224, 4096, 4096, 4240, 4240, 4112, 4096, 4240, 4224, 4112, 4096, 4224, 4224, 4096,
4096, 4224, 4224, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4224, 4096, 4096,
4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224,
4096, 4096, 4096, 4240, 4224, 4112, 4096, 4240, 4096, 4112, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096,
4096, 4096, 4224, 4096, 4096, 4096, 4224, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4097, 4096, 4096, 4100, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4224, 4225, 4096, 4096, 4224, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4224, 4224, 4096, 4096, 4224, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4609, 4608, 4608, 4612, 4612, 4608, 4608, 4608, 4608, 4608, 4096, 4608, 4608, 4096, 4096, 4624, 4624,
4624, 4608, 4628, 4624, 4624, 4608, 4608, 4608, 4608, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4608, 4096, 4608,
4096, 4608, 4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4608, 4608, 4608,
4612, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4624, 4608, 4624, 4608, 4628, 4608, 4624, 4608, 4608, 4096, 4608, 4096, 4608,
4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608,
4608, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4609, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4096,
4096, 4624, 4624, 4112, 4096, 4624, 4608, 4112, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4096, 4096, 4096,
4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608,
4608, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4624, 4608, 4112, 4096, 4624, 4096, 4112, 4096, 4608, 4096,
4096, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4096,
4096, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4100, 4100, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6144, 6145, 6144, 6144, 6148, 6148,
6144, 6144, 6152, 6152, 6152, 6144, 6152, 6152, 6144, 6144, 6160, 6160, 6160, 6144, 6164, 6160, 6160, 6144, 6160, 6160, 6160, 6144, 6160, 6160, 6144,
6144, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096, 6152, 6144, 6152, 4096, 6152, 6144, 6144, 4096, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096,
6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6208, 6208, 6144, 6144, 6212, 6208, 6144, 6144, 6216, 6208, 6152, 6144, 6216, 6208, 6144, 6144, 6224,
6208, 6160, 6144, 6228, 6208, 6160, 6144, 6224, 6208, 6160, 6144, 6224, 6208, 6144, 6144, 6144, 6144, 4096, 4096, 6148, 6144, 4096, 4096, 6152, 6144,
4104, 4096, 6152, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6148, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6145, 6144,
6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6160, 6160, 6160, 6144, 6160, 6144, 6160, 6144, 6144, 6144, 6144, 6144,
6144, 6144, 6144, 6144, 6144, 6144, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 6144, 6144, 4096, 6144,
4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6208, 6208, 6144, 6144, 6208, 6144, 6144, 6144, 6208, 6144, 6144, 6144, 6208, 6144,
6144, 6144, 6224, 6208, 6160, 6144, 6224, 6144, 6160, 6144, 6208, 6144, 6144, 6144, 6208, 6144, 6144, 6144, 6144, 6144, 4096, 4096, 6144, 4096, 4096,
4096, 6144, 4096, 4096, 4096, 6144, 4096, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
6144, 6145, 6144, 6144, 6148, 6148, 6144, 6144, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096, 6144,
6144, 6144, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6144, 6144,
6144, 4096, 6148, 6144, 6144, 4096, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6208, 6208, 6144, 6144, 6212, 6208, 6144, 6144, 6208, 6144, 6144,
4096, 6208, 6144, 4096, 4096, 6208, 6144, 6144, 4096, 6212, 6144, 6144, 4096, 6208, 6144, 6144, 4096, 6208, 6144, 4096, 4096, 6144, 6144, 4096, 4096,
6148, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6148, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144,
6144, 4096, 4096, 6144, 6145, 6144, 6144, 6144, 6144, 6144, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6144, 6144, 6144, 4096, 6144, 4096,
6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6144, 6144, 6144, 4096, 6144, 4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 6144, 6144, 6144, 4096, 6144, 4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6208, 6208, 6144, 6144, 6208, 6144, 6144, 6144,
4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 6208, 6144, 6144, 4096, 6208, 4096, 6144, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 6144,
6144, 4096, 4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 6656, 6657, 6656, 6656, 6660, 6660, 6656, 6656, 6656, 6656, 6656, 6144, 6656, 6656, 6144, 6144, 6672, 6672, 6672,
6656, 6676, 6672, 6672, 6656, 6656, 6656, 6656, 6144, 6656, 6656, 6144, 6144, 6656, 6656, 6656, 4608, 6660, 6656, 6656, 4608, 6656, 6144, 6656, 4096,
6656, 6144, 6144, 4096, 6656, 6656, 6656, 4608, 6660, 6656, 6656, 4608, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6720, 6720, 6656, 6656, 6724,
6720, 6656, 6656, 6720, 6656, 6656, 6144, 6720, 6656, 6144, 6144, 6736, 6720, 6672, 6656, 6740, 6720, 6672, 6656, 6720, 6656, 6656, 6144, 6720, 6656,
6144, 6144, 6656, 6656, 4608, 4608, 6660, 6656, 4608, 4608, 6656, 6144, 4608, 4096, 6656, 6144, 4096, 4096, 6656, 6656, 4608, 4608, 6660, 6656, 4608,
4608, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6145, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144,
6160, 6160, 6160, 6144, 6160, 6144, 6160, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 4096, 6144, 4096, 6144, 4096, 6144,
4096, 6144, 4096, 6144, 4096, 6144, 4096, 6144, 6144, 6144, 4096, 6144, 4096, 6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6208, 6208,
6144, 6144, 6208, 6144, 6144, 6144, 6208, 6144, 6144, 6144, 6208, 6144, 6144, 6144, 6224, 6208, 6160, 6144, 6224, 6144, 6160, 6144, 6208, 6144, 6144,
6144, 6208, 6144, 6144, 6144, 6144, 6144, 4096, 4096, 6144, 4096, 4096, 4096, 6144, 4096, 4096, 4096, 6144, 4096, 4096, 4096, 6144, 6144, 4096, 4096,
6144, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 6144, 6145, 6144, 6144, 6148, 6148, 6144, 6144, 6144, 6144, 6144, 4096, 6144,
6144, 4096, 4096, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 6144, 4096, 6148, 6144,
6144, 4096, 6144, 6144, 6144, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 6144, 4096, 6148, 6144, 6144, 4096, 6144, 6144, 6144, 4096, 6144, 6144, 4096,
4096, 6208, 6208, 6144, 6144, 6212, 6208, 6144, 6144, 6208, 6144, 6144, 4096, 6208, 6144, 4096, 4096, 6208, 6144, 6144, 4096, 6212, 6144, 6144, 4096,
6208, 6144, 6144, 4096, 6208, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6148, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144,
6144, 4096, 4096, 6148, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 6144, 6144, 4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4160, 4160, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160,
4096, 4096, 4096, 4160, 4096, 4096, 4096, 4160, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4100, 4100, 4096,
4096, 4104, 4104, 4104, 4096, 4104, 4104, 4096, 4096, 4112, 4112, 4112, 4096, 4116, 4112, 4112, 4096, 4112, 4112, 4112, 4096, 4112, 4112, 4096, 4096,
4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104, 4096, 4104, 4096, 4104, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104, 4096, 4104, 4096, 4104, 4096, 4096, 4096, 4112, 4096,
4112, 4096, 4116, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4104, 4096, 4104,
4096, 4104, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4112, 4112, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4112, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4097, 4096, 4096, 4100, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4608, 4609, 4608, 4608, 4612, 4612, 4608, 4608, 4608, 4608, 4608, 4096, 4608, 4608, 4096, 4096, 4624, 4624, 4624, 4608,
4628, 4624, 4624, 4608, 4608, 4608, 4608, 4096, 4608, 4608, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608,
4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608,
4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4624, 4608, 4624, 4608, 4628, 4608, 4624, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096,
4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608, 4608, 4096, 4608, 4096, 4608, 4096, 4096, 4096, 4608, 4608, 4608, 4608, 4612, 4608, 4608, 4608,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4112,
4112, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4112, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4100, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4100, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4097, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196,
8200, 8200, 8202, 8200, 8200, 8200, 8200, 8200, 8208, 8208, 8210, 8208, 8212, 8208, 8212, 8208, 8208, 8208, 8210, 8208, 8208, 8208, 8208, 8208, 8224,
8224, 8226, 8224, 8228, 8224, 8228, 8224, 8232, 8224, 8234, 8224, 8232, 8224, 8232, 8224, 8224, 8224, 8226, 8224, 8228, 8224, 8228, 8224, 8224, 8224,
8226, 8224, 8224, 8224, 8224, 8224, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8264, 8256, 8264, 8256, 8264, 8256, 8256, 8256, 8272, 8256, 8272,
8256, 8276, 8256, 8272, 8256, 8272, 8256, 8272, 8256, 8272, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8264, 8256, 8264, 8256,
8264, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8256, 8192, 8193, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192,
8272, 8256, 8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193,
8194, 8194, 8196, 8196, 8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192,
8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8192, 8256, 8192, 8256,
8192, 8192, 8192, 8256, 8192, 8256, 8192, 8260, 8192, 8256, 8192, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192,
8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8210, 8208, 8212,
8208, 8212, 8208, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8224, 8224, 8226, 8224, 8228, 8224, 8228, 8224, 8224, 8192, 8226, 8192, 8224, 8192,
8224, 8192, 8224, 8224, 8226, 8224, 8228, 8224, 8228, 8224, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256,
8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8272, 8256, 8276, 8256, 8272, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192,
8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208,
8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224,
8192, 8224, 8192, 8224, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192,
8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192,
8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256,
8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8256, 8192, 8260, 8192, 8256, 8192, 8256, 8192,
8256, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200,
8200, 8200, 8192, 8200, 8200, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8208, 8192, 8208, 8192,
8212, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208,
8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192,
8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208,
8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208,
8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200, 8200,
8200, 8192, 8200, 8200, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8224, 8224, 8224,
8192, 8228, 8224, 8224, 8192, 8232, 8224, 8232, 8192, 8232, 8224, 8224, 8192, 8224, 8224, 8224, 8192, 8228, 8224, 8224, 8192, 8224, 8224, 8224, 8192,
8224, 8224, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8264, 8256, 8200, 8192, 8264, 8256, 8192, 8192, 8272, 8256, 8208, 8192, 8276,
8256, 8208, 8192, 8272, 8256, 8208, 8192, 8272, 8256, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8264, 8256, 8200, 8192, 8264, 8256,
8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8256, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256,
8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192,
8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8256, 8192, 8192, 8192, 8260, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192,
8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8224, 8224, 8224, 8192, 8228, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192,
8224, 8224, 8224, 8192, 8228, 8224, 8224, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8256,
8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8276, 8256, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256,
8192, 8192, 8260, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192,
8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224, 8192, 8224,
8192, 8224, 8192, 8224, 8224, 8224, 8192, 8224, 8192, 8224, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192,
8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192,
8192, 8260, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8260, 8192, 8192, 8192, 8256, 8192, 8192, 8192,
8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200, 8200, 8200,
8192, 8200, 8200, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192,
8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208,
8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208,
8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196, 8200, 8200, 8202, 8200,
8200, 8200, 8200, 8200, 8208, 8208, 8210, 8208, 8212, 8208, 8212, 8208, 8208, 8208, 8210, 8208, 8208, 8208, 8208, 8208, 8192, 8192, 8194, 8192, 8196,
8192, 8196, 8192, 8200, 8192, 8202, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192,
8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8264, 8256, 8264, 8256, 8264, 8256, 8256, 8256, 8272, 8256, 8272, 8256, 8276, 8256, 8272,
8256, 8272, 8256, 8272, 8256, 8272, 8256, 8256, 8256, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192,
8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8194, 8194, 8196, 8196,
8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192,
8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8256, 8192, 8260, 8192, 8256, 8192, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192,
8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8210, 8208, 8212, 8208, 8212, 8208, 8192,
8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260, 8256, 8256, 8256, 8256, 8192, 8256,
8192, 8256, 8192, 8192, 8192, 8272, 8256, 8272, 8256, 8276, 8256, 8272, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192,
8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192,
8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8194, 8194, 8196, 8196, 8196, 8196, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194,
8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8194, 8192, 8196, 8192, 8196, 8192, 8192, 8192, 8194, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8256, 8256, 8260,
8256, 8256, 8256, 8256, 8192, 8256, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8256, 8192, 8260, 8192, 8256, 8192, 8256, 8192, 8256, 8192, 8256, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256,
8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200, 8200, 8200, 8192, 8200,
8200, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192,
8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208,
8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200, 8200, 8200, 8192, 8200, 8200,
8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192,
8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8264, 8256, 8200, 8192, 8264, 8256, 8192, 8192, 8272, 8256, 8208, 8192, 8276, 8256, 8208, 8192, 8272,
8256, 8208, 8192, 8272, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8272, 8192,
8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192,
8192, 8260, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192,
8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193,
8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8192, 8192, 8272, 8256, 8208, 8192, 8276, 8256, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192,
8192, 8192, 8256, 8192, 8192, 8192, 8272, 8256, 8208, 8192, 8272, 8192, 8208, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192, 8260, 8256, 8192,
8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8260, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8256, 8256, 8192, 8192,
8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256, 8192, 8192, 8192, 8256,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8200, 8200, 8200, 8192, 8200, 8200, 8192,
8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8208, 8208, 8208, 8192, 8208, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192,
8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192, 8208, 8192,
8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8200, 8192, 8200, 8192, 8200, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192,
8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8212, 8208, 8208, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8208, 8192, 8208, 8192, 8212, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8208, 8208, 8208, 8192, 8208, 8192, 8208, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8208, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8193, 8192, 8192, 8196, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8196, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8193, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
};
}
}
}
#endif

@ -0,0 +1,312 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// MergeTree.h - class representing the merge tree
//
//=======================================================================================
//
// COMMENTS:
//
// If we have computed the merge max & merge saddles correctly, we have substantially
// computed the merge tree already. However, it is not in the same format as we have
// previously represented it - in particular, we have yet to define all the merge arcs
// and the superarcs we have collected are not the same as before - i.e. they are already
// partially collapsed, but not according to the same rule as branch decomposition
// This unit is therefore to get the same result out as before so we can set up an
// automated crosscheck on the computation
//
// Compared to earlier versions, we have made a significant change - the merge tree
// is only computed on critical points, not on the full array. We therefore have a
// final step: to extend it to the full array. To do this, we will keep the initial
// mergeArcs array which records a maximum for each vertex, as we need the information
//
// Each maximum is now labelled with the saddle it is mapped to, or to the global min
// We therefore transfer this information back to the mergeArcs array, so that maxima
// (including saddles) are marked with the (lower) vertex that is the low end of their
// arc
// BIG CHANGE: we can actually reuse the mergeArcs array for the final merge arc, for the
// chain maximum for each (regular) point, and for the merge saddle for maxima. This is
// slightly tricky and has some extra memory traffic, but it avoids duplicating arrays
// unnecessarily
//
// Initially, mergeArcs will be set to an outbound neighbour (or self for extrema), as the
// chainMaximum array used to be.
//
// After chains are built, then it will hold *AN* accessible extremum for each vertex.
//
// During the main processing, when an extremum is assigned a saddle, it will be stored
// here. Regular points will still store pointers to an extremum.
//
// After this is done, if the mergeArc points lower/higher, it is pointing to a saddle.
// Otherwise it is pointing to an extremum.
//
// And after the final pass, it will always point to the next along superarcs.
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mergetree_h
#define vtkm_worklet_contourtree_mergetree_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/worklet/contourtree/ChainDoubler.h>
#include <vtkm/worklet/contourtree/JoinSuperArcFinder.h>
#include <vtkm/worklet/contourtree/JoinArcConnector.h>
#include <vtkm/worklet/contourtree/VertexMergeComparator.h>
//#define DEBUG_PRINT 1
//#define DEBUG_FUNCTION_ENTRY 1
//#define DEBUG_TIMING 1
namespace vtkm {
namespace worklet {
namespace contourtree {
template <typename T, typename StorageType, typename DeviceAdapter>
class MergeTree
{
public:
typedef typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter> DeviceAlgorithm;
vtkm::Id nRows, nCols, nSlices, nVertices, nLogSteps;
// original data array
const vtkm::cont::ArrayHandle<T,StorageType> &values;
// device
DeviceAdapter device;
// whether it is join or split tree
bool isJoinTree;
// vector of arcs representing the merge tree
vtkm::cont::ArrayHandle<vtkm::Id> mergeArcs;
// vector storing an extremum for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> extrema;
// vector storing a saddle for each vertex
vtkm::cont::ArrayHandle<vtkm::Id> saddles;
// merge tree constructor
MergeTree(const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices,
bool IsJoinTree);
// routine that does pointer-doubling in the mergeArc array
void BuildRegularChains();
// routine that computes the augmented merge tree superarcs from the merge graph
void ComputeAugmentedSuperarcs();
// routine that computes the augmented merge arcs from the superarcs
// this is separate from the previous routine because it also gets called separately
// once saddle & extrema are set for a given set of vertices, the merge arcs can be
// computed for any subset of those vertices that contains all of the critical points
void ComputeAugmentedArcs(vtkm::cont::ArrayHandle<vtkm::Id> &vertices);
// debug routine
void DebugPrint(const char *message);
};
// creates merge tree
template <typename T, typename StorageType, typename DeviceAdapter>
MergeTree<T,StorageType,DeviceAdapter>::MergeTree(
const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices,
bool IsJoinTree) : values(Values),
device(Device),
nRows(NRows),
nCols(NCols),
nSlices(NSlices),
isJoinTree(IsJoinTree)
{
nVertices = nRows * nCols * nSlices;
nLogSteps = 1;
for (vtkm::Id shifter = nVertices; shifter != 0; shifter >>= 1)
nLogSteps++;
vtkm::cont::ArrayHandleConstant<vtkm::Id> nullArray(0, nVertices);
mergeArcs.Allocate(nVertices);
extrema.Allocate(nVertices);
saddles.Allocate(nVertices);
DeviceAlgorithm::Copy(nullArray, mergeArcs);
DeviceAlgorithm::Copy(nullArray, extrema);
DeviceAlgorithm::Copy(nullArray, saddles);
}
// routine that does pointer-doubling in the saddles array
template<typename T, typename StorageType, typename DeviceAdapter>
void MergeTree<T,StorageType,DeviceAdapter>::BuildRegularChains()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "====================" << endl;
cout << "Build Regular Chains" << endl;
cout << "====================" << endl;
cout << endl;
#endif
// 2. Create a temporary array so that we can alternate writing between them
vtkm::cont::ArrayHandle<vtkm::Id> temporaryArcs;
temporaryArcs.Allocate(nVertices);
vtkm::cont::ArrayHandleIndex vertexIndexArray(nVertices);
ChainDoubler chainDoubler;
vtkm::worklet::DispatcherMapField<ChainDoubler> chainDoublerDispatcher(chainDoubler);
// 3. Apply pointer-doubling to build chains to maxima, rocking between two arrays
for (vtkm::Id logStep = 0; logStep < nLogSteps; logStep++)
{
chainDoublerDispatcher.Invoke(vertexIndexArray, // input
extrema); // i/o whole array
}
} // BuildRegularChains()
// routine that computes the augmented merge tree from the merge graph
template <typename T, typename StorageType, typename DeviceAdapter>
void MergeTree<T,StorageType,DeviceAdapter>::ComputeAugmentedSuperarcs()
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "=================================" << endl;
cout << "Compute Augmented Merge Superarcs" << endl;
cout << "=================================" << endl;
cout << endl;
#endif
// our first step is to assign every vertex to a pseudo-extremum based on how the
// vertex ascends to a extremum, and the sequence of pruning for the extremum
// to do this, we iterate as many times as pruning occurred
// we run a little loop for each element until it finds its join superarc
// expressed as a functor.
vtkm::Id nExtrema = extrema.GetNumberOfValues();
JoinSuperArcFinder<T> joinSuperArcFinder(isJoinTree);
vtkm::worklet::DispatcherMapField<JoinSuperArcFinder<T> >
joinSuperArcFinderDispatcher(joinSuperArcFinder);
vtkm::cont::ArrayHandleIndex vertexIndexArray(nExtrema);
joinSuperArcFinderDispatcher.Invoke(vertexIndexArray, // input
values, // input (whole array)
saddles, // i/o (whole array)
extrema); // i/o (whole array)
// at the end of this, all vertices should have a pseudo-extremum in the extrema array
// and a pseudo-saddle in the saddles array
#ifdef DEBUG_PRINT
//DebugPrint("Merge Superarcs Set");
#endif
} // ComputeAugmentedSuperarcs()
// routine that computes the augmented merge arcs from the superarcs
// this is separate from the previous routine because it also gets called separately
// once saddle & extrema are set for a given set of vertices, the merge arcs can be
// computed for any subset of those vertices that contains all of the critical points
template <typename T, typename StorageType, typename DeviceAdapter>
void MergeTree<T,StorageType,DeviceAdapter>::ComputeAugmentedArcs(
vtkm::cont::ArrayHandle<vtkm::Id> &vertices)
{
#ifdef DEBUG_FUNCTION_ENTRY
cout << endl;
cout << "============================" << endl;
cout << "Compute Augmented Merge Arcs" << endl;
cout << "============================" << endl;
cout << endl;
#endif
// create a vector of indices for sorting
vtkm::Id nCriticalVerts = vertices.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::Id> vertexSorter;
DeviceAlgorithm::Copy(vertices, vertexSorter);
// We sort by pseudo-maximum to establish the extents
DeviceAlgorithm::Sort(vertexSorter,
VertexMergeComparator<T,StorageType,DeviceAdapter>(
values.PrepareForInput(device),
extrema.PrepareForInput(device),
isJoinTree));
#ifdef DEBUG_PRINT
//DebugPrint("Sorting Complete");
#endif
vtkm::cont::ArrayHandleConstant<vtkm::Id> noVertArray(NO_VERTEX_ASSIGNED, nVertices);
DeviceAlgorithm::Copy(noVertArray, mergeArcs);
vtkm::cont::ArrayHandleIndex critVertexIndexArray(nCriticalVerts);
JoinArcConnector joinArcConnector;
vtkm::worklet::DispatcherMapField<JoinArcConnector>
joinArcConnectorDispatcher(joinArcConnector);
joinArcConnectorDispatcher.Invoke(critVertexIndexArray, // input
vertexSorter, // input (whole array)
extrema, // input (whole array)
saddles, // input (whole array)
mergeArcs); // output (whole array)
#ifdef DEBUG_PRINT
//DebugPrint("Augmented Arcs Set");
#endif
} // ComputeAugmentedArcs()
// debug routine
template<typename T, typename StorageType, typename DeviceAdapter>
void MergeTree<T,StorageType,DeviceAdapter>::DebugPrint(const char *message)
{
cout << "DebugPrint in MergeTree called" << endl;
/*
std::cout << "---------------------------" << std::endl;
std::cout << string(message) << std::endl;
std::cout << "---------------------------" << std::endl;
std::cout << std::endl;
printLabelledBlock("Values", values, nRows*nSlices, nCols);
std::cout << std::endl;
printLabelledBlock("MergeArcs", mergeArcs, nRows, nCols);
std::cout << std::endl;
printLabelledBlock("Extrema", extrema, nRows, nCols);
std::cout << std::endl;
printLabelledBlock("Saddles", saddles, nRows, nCols);
std::cout << std::endl;
*/
} // DebugPrint()
}
}
}
#endif

@ -0,0 +1,181 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_SaddleStarter.h - fills in saddle ascents per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh2d_dem_saddle_starter_h
#define vtkm_worklet_contourtree_mesh2d_dem_saddle_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation_Macros.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class Mesh2D_DEM_SaddleStarter : public vtkm::worklet::WorkletMapField
{
public:
struct PairType : vtkm::ListTagBase<vtkm::Pair<vtkm::Id, vtkm::Id> > {};
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into active vertices
FieldIn<PairType> outDegFirstEdge, // (input) out degree/first edge of vertex
FieldIn<IdType> valueIndex, // (input) index into regular graph
WholeArrayIn<IdType> linkMask, // (input) neighbors of vertex
WholeArrayIn<IdType> arcArray, // (input) chain extrema per vertex
WholeArrayIn<IdType> inverseIndex, // (input) permutation of index
WholeArrayOut<IdType> edgeNear, // (output) low end of edges
WholeArrayOut<IdType> edgeFar, // (output) high end of edges
WholeArrayOut<IdType> activeEdges); // (output) active edge list
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8, _9);
typedef _1 InputDomain;
vtkm::Id nRows; // (input) number of rows in 2D
vtkm::Id nCols; // (input) number of cols in 2D
bool ascending; // (input) ascending or descending (join or split)
// Constructor
VTKM_EXEC_CONT
Mesh2D_DEM_SaddleStarter(vtkm::Id NRows,
vtkm::Id NCols,
bool Ascending) : nRows(NRows),
nCols(NCols),
ascending(Ascending) {}
// operator() routine that executes the loop
template<typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const vtkm::Pair<vtkm::Id,vtkm::Id>& outDegFirstEdge,
const vtkm::Id& valueIndex,
const InFieldPortalType& linkMask,
const InFieldPortalType& arcArray,
const InFieldPortalType& inverseIndex,
const OutFieldPortalType& edgeNear,
const OutFieldPortalType& edgeFar,
const OutFieldPortalType& activeEdges) const
{
vtkm::Id outdegree = outDegFirstEdge.first;
vtkm::Id firstEdge = outDegFirstEdge.second;
// skip local extrema
if (outdegree == 0)
return;
// get the saddle mask for the vertex
vtkm::Id nbrMask = linkMask.Get(valueIndex);
// get the row and column
vtkm::Id row = VERTEX_ROW(valueIndex, nCols);
vtkm::Id col = VERTEX_COL(valueIndex, nCols);
// we now know which edges are starts, so we count to get the outdegree
vtkm::Id outDegree = 0;
vtkm::Id farEnds[MAX_OUTDEGREE];
// copy into the temporary array
if ((nbrMask & 0x30) == 0x20)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row-1, col, nCols)));
if ((nbrMask & 0x18) == 0x10)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row-1, col-1, nCols)));
if ((nbrMask & 0x0C) == 0x08)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row, col-1, nCols)));
if ((nbrMask & 0x06) == 0x04)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row+1, col, nCols)));
if ((nbrMask & 0x03) == 0x02)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row+1, col+1, nCols)));
if ((nbrMask & 0x21) == 0x01)
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(VERTEX_ID(row, col+1, nCols)));
// now we check them against each other
if ((outDegree == 2) && (farEnds[0] == farEnds[1]))
{ // outDegree 2 & both match
// treat as a regular point
outDegree = 1;
} // outDegree 2 & both match
else if (outDegree == 3)
{ // outDegree 3
if (farEnds[0] == farEnds[1])
{ // first two match
if (farEnds[0] == farEnds[2])
{ // triple match
// all match - treat as regular point
outDegree = 1;
} // triple match
else
{ // first two match, but not third
// copy third down one place
farEnds[1] = farEnds[2];
// and reset the count
outDegree = 2;
} //
} // first two match
else if ((farEnds[0] == farEnds[2]) || (farEnds[1] == farEnds[2]))
{ // second one matches either of the first two
// decrease the count, keeping 0 & 1
outDegree = 2;
} // second one matches either of the first two
} // outDegree 3
// now the farEnds array holds the far ends we can reach
for (vtkm::Id edge = 0; edge < outDegree; edge++)
{
// compute the edge index in the edge arrays
vtkm::Id edgeID = firstEdge + edge;
// now set the near and far ends and save the edge itself
edgeNear.Set(edgeID, vertex);
edgeFar.Set(edgeID, farEnds[edge]);
activeEdges.Set(edgeID, edgeID);
} // per start
} // operator()
}; // Mesh2D_DEM_SaddleStarter
}
}
}
#endif

@ -0,0 +1,241 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_Triangulation.h - class representing the topology of a 2D triangulation read
// in from a DEM - initially in ASCII text
//
//=======================================================================================
//
// COMMENTS:
//
// Essentially, a vector of data values. BUT we will want them sorted to simplify
// processing - i.e. it's the robust way of handling simulation of simplicity
//
// On the other hand, once we have them sorted, we can discard the original data since
// only the sort order matters
//
// Since we've been running into memory issues, we'll start being more careful.
// Clearly, we can eliminate the values if we sort, but in this iteration we are
// deferring doing a full sort, so we need to keep the values.
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh2d_dem_triangulation_h
#define vtkm_worklet_contourtree_mesh2d_dem_triangulation_h
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleZip.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/contourtree/Types.h>
#include <vtkm/worklet/contourtree/ChainGraph.h>
#include <vtkm/worklet/contourtree/PrintVectors.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_VertexStarter.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_VertexOutdegreeStarter.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_SaddleStarter.h>
#define DEBUG_PRINT 1
//#define DEBUG_TIMING 1
namespace vtkm {
namespace worklet {
namespace contourtree {
template <typename T, typename StorageType, typename DeviceAdapter>
class Mesh2D_DEM_Triangulation
{
public:
typedef typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter> DeviceAlgorithm;
// size of the mesh
vtkm::Id nRows, nCols, nVertices, nLogSteps;
// original data array
const vtkm::cont::ArrayHandle<T,StorageType> &values;
// device
DeviceAdapter device;
// Array with neighbourhood masks
vtkm::cont::ArrayHandle<vtkm::Id> neighbourhoodMask;
// constructor
Mesh2D_DEM_Triangulation(const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols);
// sets all vertices to point along an outgoing edge (except extrema)
void SetStarts(vtkm::cont::ArrayHandle<vtkm::Id> &chains,
bool descending);
// sets outgoing paths for saddles
void SetSaddleStarts(ChainGraph<T,StorageType,DeviceAdapter> &mergeGraph, bool descending);
};
// sets outgoing paths for saddles
template<typename T, typename StorageType, typename DeviceAdapter>
void Mesh2D_DEM_Triangulation<T,StorageType,DeviceAdapter>::SetStarts(
vtkm::cont::ArrayHandle<vtkm::Id> &chains,
bool ascending)
{
// create the neighbourhood mask
neighbourhoodMask.Allocate(nVertices);
// For each vertex set the next vertex in the chain
vtkm::cont::ArrayHandleIndex vertexIndexArray(nVertices);
Mesh2D_DEM_VertexStarter<T> vertexStarter(nRows, nCols, ascending);
vtkm::worklet::DispatcherMapField<Mesh2D_DEM_VertexStarter<T> >
vertexStarterDispatcher(vertexStarter);
vertexStarterDispatcher.Invoke(vertexIndexArray, // input
values, // input (whole array)
chains, // output
neighbourhoodMask); // output
} // SetStarts()
// creates input mesh
template<typename T, typename StorageType, typename DeviceAdapter>
Mesh2D_DEM_Triangulation<T,StorageType,DeviceAdapter>::Mesh2D_DEM_Triangulation(
const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols) :
values(Values),
device(Device),
nRows(NRows),
nCols(NCols)
{
nVertices = nRows * nCols;
// compute the number of log-jumping steps (i.e. lg_2 (nVertices))
nLogSteps = 1;
for (signed long shifter = nVertices; shifter > 0; shifter >>= 1)
nLogSteps++;
}
// sets outgoing paths for saddles
template<typename T, typename StorageType, typename DeviceAdapter>
void Mesh2D_DEM_Triangulation<T,StorageType,DeviceAdapter>::SetSaddleStarts(ChainGraph<T,StorageType,DeviceAdapter> &mergeGraph,
bool ascending)
{
// we need a temporary inverse index to change vertex IDs
vtkm::cont::ArrayHandle<vtkm::Id> inverseIndex;
vtkm::cont::ArrayHandle<vtkm::Id> isCritical;
vtkm::cont::ArrayHandle<vtkm::Id> outdegree;
inverseIndex.Allocate(nVertices);
isCritical.Allocate(nVertices);
outdegree.Allocate(nVertices);
vtkm::cont::ArrayHandleIndex vertexIndexArray(nVertices);
Mesh2D_DEM_VertexOutdegreeStarter vertexOutdegreeStarter(nRows,
nCols,
ascending);
vtkm::worklet::DispatcherMapField<Mesh2D_DEM_VertexOutdegreeStarter>
vertexOutdegreeStarterDispatcher(vertexOutdegreeStarter);
vertexOutdegreeStarterDispatcher.Invoke(vertexIndexArray, // input
neighbourhoodMask, // input
mergeGraph.arcArray, // input (whole array)
outdegree, // output
isCritical); // output
DeviceAlgorithm::ScanExclusive(isCritical, inverseIndex);
// now we can compute how many critical points we carry forward
vtkm::Id nCriticalPoints = inverseIndex.GetPortalConstControl().Get(nVertices-1) +
isCritical.GetPortalConstControl().Get(nVertices-1);
// allocate space for the join graph vertex arrays
mergeGraph.AllocateVertexArrays(nCriticalPoints);
// compact the set of vertex indices to critical ones only
DeviceAlgorithm::StreamCompact(vertexIndexArray, isCritical, mergeGraph.valueIndex);
// we initialise the prunesTo array to "NONE"
vtkm::cont::ArrayHandleConstant<vtkm::Id> notAssigned(NO_VERTEX_ASSIGNED, nCriticalPoints);
DeviceAlgorithm::Copy(notAssigned, mergeGraph.prunesTo);
// copy the outdegree from our temporary array
// : mergeGraph.outdegree[vID] <= outdegree[mergeGraph.valueIndex[vID]]
DeviceAlgorithm::StreamCompact(outdegree, isCritical, mergeGraph.outdegree);
// copy the chain maximum from arcArray
// : mergeGraph.chainExtremum[vID] = inverseIndex[mergeGraph.arcArray[mergeGraph.valueIndex[vID]]]
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdArrayType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, IdArrayType> PermuteIndexType;
vtkm::cont::ArrayHandle<vtkm::Id> tArray;
tArray.Allocate(nCriticalPoints);
DeviceAlgorithm::StreamCompact(mergeGraph.arcArray, isCritical, tArray);
DeviceAlgorithm::Copy(PermuteIndexType(tArray, inverseIndex), mergeGraph.chainExtremum);
// and set up the active vertices - initially to identity
vtkm::cont::ArrayHandleIndex criticalVertsIndexArray(nCriticalPoints);
DeviceAlgorithm::Copy(criticalVertsIndexArray, mergeGraph.activeVertices);
// now we need to compute the firstEdge array from the outdegrees
DeviceAlgorithm::ScanExclusive(mergeGraph.outdegree, mergeGraph.firstEdge);
vtkm::Id nCriticalEdges = mergeGraph.firstEdge.GetPortalConstControl().Get(nCriticalPoints-1) +
mergeGraph.outdegree.GetPortalConstControl().Get(nCriticalPoints-1);
// now we allocate the edge arrays
mergeGraph.AllocateEdgeArrays(nCriticalEdges);
// and we have to set them, so we go back to the vertices
Mesh2D_DEM_SaddleStarter saddleStarter(nRows, // input
nCols, // input
ascending); // input
vtkm::worklet::DispatcherMapField<Mesh2D_DEM_SaddleStarter>
saddleStarterDispatcher(saddleStarter);
vtkm::cont::ArrayHandleZip<vtkm::cont::ArrayHandle<vtkm::Id>, vtkm::cont::ArrayHandle<vtkm::Id> > outDegFirstEdge =
vtkm::cont::make_ArrayHandleZip(mergeGraph.outdegree, mergeGraph.firstEdge);
saddleStarterDispatcher.Invoke(criticalVertsIndexArray, // input
outDegFirstEdge, // input (pair)
mergeGraph.valueIndex, // input
neighbourhoodMask, // input (whole array)
mergeGraph.arcArray, // input (whole array)
inverseIndex, // input (whole array)
mergeGraph.edgeNear, // output (whole array)
mergeGraph.edgeFar, // output (whole array)
mergeGraph.activeEdges); // output (whole array)
// finally, allocate and initialise the edgeSorter array
DeviceAlgorithm::Copy(mergeGraph.activeEdges, mergeGraph.edgeSorter);
} // SetSaddleStarts()
}
}
}
#endif

@ -0,0 +1,52 @@
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_Macros.h - macros for working with 2D DEM triangulations
//
//=======================================================================================
//
// COMMENTS:
//
// Essentially, a vector of data values. BUT we will want them sorted to simplify
// processing - i.e. it's the robust way of handling simulation of simplicity
//
// On the other hand, once we have them sorted, we can discard the original data since
// only the sort order matters
//
//=======================================================================================
// macro definitions
#define N_EDGE_TYPES 3
#define EDGE_TYPE_HORIZONTAL 0
#define EDGE_TYPE_VERTICAL 1
#define EDGE_TYPE_DIAGONAL 2
#define N_INCIDENT_EDGES 6
#define MAX_OUTDEGREE 3
// vertex row - integer divide by columns
#define VERTEX_ROW(V,NCOLS) ((V)/(NCOLS))
// vertex column - integer modulus by columns
#define VERTEX_COL(V,NCOLS) ((V)%(NCOLS))
// vertex ID - row * ncols + col
#define VERTEX_ID(R,C,NCOLS) ((R)*(NCOLS)+(C))
// edge row - edge / (ncols * nEdgeTypes)
#define EDGE_ROW(E,NCOLS) ((E)/((NCOLS)*(N_EDGE_TYPES)))
// edge col - (edge / nEdgeTypes) % nCols
#define EDGE_COL(E,NCOLS) (((E)/(N_EDGE_TYPES))%(NCOLS))
// edge which - edge % nEdgeTypes
#define EDGE_WHICH(E) ((E)%(N_EDGE_TYPES))
// edge ID - (row * ncols + col) * nEdgeTypes + which
#define EDGE_ID(R,C,W,NCOLS) ((((R)*(NCOLS)+(C))*(N_EDGE_TYPES))+(W))
// edge from - vertex with same row & col
#define EDGE_FROM(E,NCOLS) VERTEX_ID(EDGE_ROW(E,NCOLS),EDGE_COL(E,NCOLS),NCOLS)
// edge to - edge from +1 col if not vertical, +1 row if not horizontal
#define EDGE_TO(E,NCOLS) VERTEX_ID(EDGE_ROW(E,NCOLS)+((EDGE_WHICH(E)==EDGE_TYPE_HORIZONTAL)?0:1),EDGE_COL(E,NCOLS)+((EDGE_WHICH(E)==EDGE_TYPE_VERTICAL)?0:1),NCOLS)

@ -0,0 +1,161 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_VertexOutdegreeStarter.h - computes how many unique starts per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh2d_dem_vertex_outdegree_starter_h
#define vtkm_worklet_contourtree_mesh2d_dem_vertex_outdegree_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation_Macros.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class Mesh2D_DEM_VertexOutdegreeStarter : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into active vertices
FieldIn<IdType> nbrMask, // (input) neighbor mask
WholeArrayIn<IdType> arcArray, // (input) chain extrema
FieldOut<IdType> outdegree, // (output) outdegree
FieldOut<IdType> isCritical); // (output) whether critical
typedef void ExecutionSignature(_1, _2, _3, _4, _5/*, _6*/);
typedef _1 InputDomain;
vtkm::Id nRows; // (input) number of rows in 2D
vtkm::Id nCols; // (input) number of cols in 2D
bool ascending; // (input) ascending or descending (join or split tree)
// Constructor
VTKM_EXEC_CONT
Mesh2D_DEM_VertexOutdegreeStarter(vtkm::Id NRows,
vtkm::Id NCols,
bool Ascending) : nRows(NRows),
nCols(NCols),
ascending(Ascending) {}
//template<typename InFieldPortalType>
template<typename InFieldPortalType/*, typename InOutFieldPortalType*/>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const vtkm::Id& nbrMask,
const InFieldPortalType& arcArray,
vtkm::Id& outdegree,
vtkm::Id& isCritical) const
{
// get the row and column
vtkm::Id row = VERTEX_ROW(vertex, nCols);
vtkm::Id col = VERTEX_COL(vertex, nCols);
// we know which edges are outbound, so we count to get the outdegree
vtkm::Id outDegree = 0;
vtkm::Id farEnds[MAX_OUTDEGREE];
// special case for local extremum
if (nbrMask == 0x3F) {
outDegree = 1;
}
else { // not a local minimum
if ((nbrMask & 0x30) == 0x20)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row-1, col, nCols));
if ((nbrMask & 0x18) == 0x10)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row-1, col-1, nCols));
if ((nbrMask & 0x0C) == 0x08)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row, col-1, nCols));
if ((nbrMask & 0x06) == 0x04)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row+1, col, nCols));
if ((nbrMask & 0x03) == 0x02)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row+1, col+1, nCols));
if ((nbrMask & 0x21) == 0x01)
farEnds[outDegree++] = arcArray.Get(VERTEX_ID(row, col+1, nCols));
} // not a local minimum
// now we check them against each other
if ((outDegree == 2) && (farEnds[0] == farEnds[1]))
{ // outDegree 2 & both match
// treat as a regular point
outDegree = 1;
} // outDegree 2 & both match
else if (outDegree == 3)
{ // outDegree 3
if (farEnds[0] == farEnds[1])
{ // first two match
if (farEnds[0] == farEnds[2])
{ // triple match
// all match - treat as regular point
outDegree = 1;
} // triple match
else
{ // first two match, but not third
// copy third down one place
farEnds[1] = farEnds[2];
// and reset the count
outDegree = 2;
} //
} // first two match
else if ((farEnds[0] == farEnds[2]) || (farEnds[1] == farEnds[2]))
{ // second one matches either of the first two
// decrease the count, keeping 0 & 1
outDegree = 2;
} // second one matches either of the first two
} // outDegree 3
// now store the outDegree
outdegree = outDegree;
// and set the initial inverse index to a flag
isCritical = (outDegree != 1) ? 1 : 0;
}
}; // Mesh2D_DEM_VertexStarter
} // namespace contourtree
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,182 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_VertexAscender.h - a functor that computes a link mask & a regular ascent
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh2d_dem_vertex_starter_h
#define vtkm_worklet_contourtree_mesh2d_dem_vertex_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation_Macros.h>
#include <vtkm/worklet/contourtree/VertexValueComparator.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
template<typename T>
class Mesh2D_DEM_VertexStarter : public vtkm::worklet::WorkletMapField
{
public:
struct TagType : vtkm::ListTagBase<T> {};
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index of vertex
WholeArrayIn<TagType> values, // (input) values within mesh
FieldOut<IdType> chain, // (output) modify the chains
FieldOut<IdType> linkMask); // (output) modify the mask
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef _1 InputDomain;
vtkm::Id nRows; // (input) number of rows in 2D
vtkm::Id nCols; // (input) number of cols in 2D
bool ascending; // ascending or descending (join or split tree)
// Constructor
VTKM_EXEC_CONT
Mesh2D_DEM_VertexStarter(vtkm::Id NRows,
vtkm::Id NCols,
bool Ascending) : nRows(NRows),
nCols(NCols),
ascending(Ascending) {}
// Locate the next vertex in direction indicated
template <typename InFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const InFieldPortalType& values,
vtkm::Id& chain,
vtkm::Id& linkMask) const
{
VertexValueComparator<InFieldPortalType> lessThan(values);
vtkm::Id row = VERTEX_ROW(vertex, nCols);
vtkm::Id col = VERTEX_COL(vertex, nCols);
vtkm::Id destination = vertex;
vtkm::Id mask = 0;
bool isLeft = (col == 0);
bool isRight = (col == nCols - 1);
bool isTop = (row == 0);
bool isBottom = (row == nRows - 1);
for (vtkm::Id edgeNo = 0; edgeNo < N_INCIDENT_EDGES; edgeNo++)
{ // per edge
vtkm::Id nbr;
switch (edgeNo)
{
case 5: // up
if (isTop)
break;
nbr = vertex - nCols;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x20;
destination = nbr;
break;
case 4: // up left
if (isLeft || isTop)
break;
nbr = vertex - nCols - 1;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x10;
destination = nbr;
break;
case 3: // left
if (isLeft)
break;
nbr = vertex - 1;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x08;
destination = nbr;
break;
case 2: // down
if (isBottom)
break;
nbr = vertex + nCols;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x04;
destination = nbr;
break;
case 1: // down right
if (isBottom || isRight)
break;
nbr = vertex + nCols + 1;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x02;
destination = nbr;
break;
case 0: // right
if (isRight)
break;
nbr = vertex + 1;
if (lessThan(vertex, nbr, ascending))
break;
mask |= 0x01;
destination = nbr;
break;
} // switch on edgeNo
} // per edge
linkMask = mask;
chain = destination;
} // operator()
}; // Mesh2D_DEM_VertexStarter
}
}
}
#endif

@ -0,0 +1,196 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_SaddleStarter.h - fills in saddle ascents per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh3d_dem_saddle_starter_h
#define vtkm_worklet_contourtree_mesh3d_dem_saddle_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_Triangulation_Macros.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
template<typename DeviceAdapter>
class Mesh3D_DEM_SaddleStarter : public vtkm::worklet::WorkletMapField
{
public:
struct PairType : vtkm::ListTagBase<vtkm::Pair<vtkm::Id, vtkm::Id> > {};
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into active vertices
FieldIn<PairType> outDegFirstEdge, // (input) out degree/first edge of vertex
FieldIn<IdType> valueIndex, // (input) index into regular graph
WholeArrayIn<IdType> linkMask, // (input) neighbors of vertex
WholeArrayIn<IdType> arcArray, // (input) chain extrema per vertex
WholeArrayIn<IdType> inverseIndex, // (input) permutation of index
WholeArrayOut<IdType> edgeNear, // (output) low end of edges
WholeArrayOut<IdType> edgeFar, // (output) high end of edges
WholeArrayOut<IdType> activeEdges); // (output) active edge list
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6, _7, _8, _9);
typedef _1 InputDomain;
typedef typename vtkm::cont::ArrayHandle<vtkm::UInt16>::template ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
IdPortalType caseTable; // (input) case table for neighbours
vtkm::Id nRows; // (input) number of rows in 3D
vtkm::Id nCols; // (input) number of cols in 3D
vtkm::Id nSlices; // (input) number of cols in 3D
bool ascending; // (input) ascending or descending (join or split)
const vtkm::IdComponent neighbourOffsets3D[N_INCIDENT_EDGES_3D][3] = {
{ -1, -1, -1 }, { 0, -1, 0 }, { -1, -1, 0 }, { -1, 0, 0 }, { -1, 0, -1 }, { 0, 0, -1 }, { 0, -1, -1 },
{ 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 }
};
// Constructor
VTKM_EXEC_CONT
Mesh3D_DEM_SaddleStarter(vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices,
bool Ascending,
IdPortalType CaseTable) :
nRows(NRows),
nCols(NCols),
nSlices(NSlices),
ascending(Ascending),
caseTable(CaseTable) {}
// operator() routine that executes the loop
template<typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const vtkm::Pair<vtkm::Id,vtkm::Id>& outDegFirstEdge,
const vtkm::Id& valueIndex,
const InFieldPortalType& linkMask,
const InFieldPortalType& arcArray,
const InFieldPortalType& inverseIndex,
const OutFieldPortalType& edgeNear,
const OutFieldPortalType& edgeFar,
const OutFieldPortalType& activeEdges) const
{
vtkm::Id outdegree = outDegFirstEdge.first;
vtkm::Id firstEdge = outDegFirstEdge.second;
// skip local extrema
if (outdegree == 0)
return;
// get the saddle mask for the vertex
vtkm::Id nbrMask = linkMask.Get(valueIndex);
// get the row and column
vtkm::Id row = VERTEX_ROW_3D(valueIndex, nRows, nCols);
vtkm::Id col = VERTEX_COL_3D(valueIndex, nRows, nCols);
vtkm::Id slice = VERTEX_SLICE_3D(valueIndex, nRows, nCols);
// we know which edges are outbound, so we count to get the outdegree
vtkm::Id outDegree = 0;
vtkm::Id farEnds[MAX_OUTDEGREE_3D];
for (vtkm::Id edgeNo = 0; edgeNo < N_INCIDENT_EDGES_3D; edgeNo++)
{
if (caseTable.Get(nbrMask) & (1 << edgeNo))
{
vtkm::Id nbrSlice = slice + neighbourOffsets3D[edgeNo][0];
vtkm::Id nbrRow = row + neighbourOffsets3D[edgeNo][1];
vtkm::Id nbrCol = col + neighbourOffsets3D[edgeNo][2];
vtkm::Id nbr = VERTEX_ID_3D(nbrSlice, nbrRow, nbrCol, nRows, nCols);
farEnds[outDegree++] = inverseIndex.Get(arcArray.Get(nbr));
}
}
// now we check them against each other
if ((outDegree == 2) && (farEnds[0] == farEnds[1]))
{ // outDegree 2 & both match
// treat as a regular point
outDegree = 1;
} // outDegree 2 & both match
else if (outDegree == 3)
{ // outDegree 3
if (farEnds[0] == farEnds[1])
{ // first two match
if (farEnds[0] == farEnds[2])
{ // triple match
// all match - treat as regular point
outDegree = 1;
} // triple match
else
{ // first two match, but not third
// copy third down one place
farEnds[1] = farEnds[2];
// and reset the count
outDegree = 2;
} //
} // first two match
else if ((farEnds[0] == farEnds[2]) || (farEnds[1] == farEnds[2]))
{ // second one matches either of the first two
// decrease the count, keeping 0 & 1
outDegree = 2;
} // second one matches either of the first two
} // outDegree 3
// now the farEnds array holds the far ends we can reach
for (vtkm::Id edge = 0; edge < outDegree; edge++)
{
// compute the edge index in the edge arrays
vtkm::Id edgeID = firstEdge + edge;
// now set the near and far ends and save the edge itself
edgeNear.Set(edgeID, vertex);
edgeFar.Set(edgeID, farEnds[edge]);
activeEdges.Set(edgeID, edgeID);
} // per start
} // operator()
}; // Mesh3D_DEM_SaddleStarter
}
}
}
#endif

@ -0,0 +1,262 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_Triangulation.h - class representing the topology of a 2D triangulation read
// in from a DEM - initially in ASCII text
//
//=======================================================================================
//
// COMMENTS:
//
// Essentially, a vector of data values. BUT we will want them sorted to simplify
// processing - i.e. it's the robust way of handling simulation of simplicity
//
// On the other hand, once we have them sorted, we can discard the original data since
// only the sort order matters
//
// Since we've been running into memory issues, we'll start being more careful.
// Clearly, we can eliminate the values if we sort, but in this iteration we are
// deferring doing a full sort, so we need to keep the values.
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh3d_dem_triangulation_h
#define vtkm_worklet_contourtree_mesh3d_dem_triangulation_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleZip.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/contourtree/Types.h>
#include <vtkm/worklet/contourtree/ChainGraph.h>
#include <vtkm/worklet/contourtree/PrintVectors.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_VertexStarter.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_VertexOutdegreeStarter.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_SaddleStarter.h>
#include <vtkm/worklet/contourtree/LinkComponentCaseTable3D.h>
#define DEBUG_PRINT 1
//#define DEBUG_TIMING 1
namespace vtkm {
namespace worklet {
namespace contourtree {
template <typename T, typename StorageType, typename DeviceAdapter>
class Mesh3D_DEM_Triangulation
{
public:
typedef typename vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter> DeviceAlgorithm;
// size of the mesh
vtkm::Id nRows, nCols, nSlices, nVertices, nLogSteps;
// original data array
const vtkm::cont::ArrayHandle<T,StorageType> &values;
// device
DeviceAdapter device;
// array with neighbourhood masks
vtkm::cont::ArrayHandle<vtkm::Id> neighbourhoodMask;
// case table information for finding neighbours
vtkm::cont::ArrayHandle<vtkm::UInt16> linkComponentCaseTable3D;
// constructor
Mesh3D_DEM_Triangulation(const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices);
// sets all vertices to point along an outgoing edge (except extrema)
void SetStarts(vtkm::cont::ArrayHandle<vtkm::Id> &chains,
bool descending);
// sets outgoing paths for saddles
void SetSaddleStarts(ChainGraph<T,StorageType,DeviceAdapter> &mergeGraph, bool descending);
};
// creates input mesh
template<typename T, typename StorageType, typename DeviceAdapter>
Mesh3D_DEM_Triangulation<T,StorageType,DeviceAdapter>::Mesh3D_DEM_Triangulation(
const vtkm::cont::ArrayHandle<T,StorageType> &Values,
DeviceAdapter Device,
vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices) :
values(Values),
device(Device),
nRows(NRows),
nCols(NCols),
nSlices(NSlices),
linkComponentCaseTable3D()
{
nVertices = nRows * nCols * nSlices;
// compute the number of log-jumping steps (i.e. lg_2 (nVertices))
nLogSteps = 1;
for (signed long shifter = nVertices; shifter > 0; shifter >>= 1)
nLogSteps++;
linkComponentCaseTable3D =
vtkm::cont::make_ArrayHandle(vtkm::worklet::contourtree::linkComponentCaseTable3D, 16384);
}
// sets outgoing paths for saddles
template<typename T, typename StorageType, typename DeviceAdapter>
void Mesh3D_DEM_Triangulation<T,StorageType,DeviceAdapter>::SetStarts(
vtkm::cont::ArrayHandle<vtkm::Id> &chains,
bool ascending)
{
// create the neighbourhood mask
neighbourhoodMask.Allocate(nVertices);
// For each vertex set the next vertex in the chain
vtkm::cont::ArrayHandleIndex vertexIndexArray(nVertices);
Mesh3D_DEM_VertexStarter<T> vertexStarter(nRows, nCols, nSlices, ascending);
vtkm::worklet::DispatcherMapField<Mesh3D_DEM_VertexStarter<T> >
vertexStarterDispatcher(vertexStarter);
vertexStarterDispatcher.Invoke(vertexIndexArray, // input
values, // input (whole array)
chains, // output
neighbourhoodMask); // output
} // SetStarts()
// sets outgoing paths for saddles
template<typename T, typename StorageType, typename DeviceAdapter>
void Mesh3D_DEM_Triangulation<T,StorageType,DeviceAdapter>::SetSaddleStarts(ChainGraph<T,StorageType,DeviceAdapter> &mergeGraph,
bool ascending)
{
// we need a temporary inverse index to change vertex IDs
vtkm::cont::ArrayHandle<vtkm::Id> inverseIndex;
vtkm::cont::ArrayHandle<vtkm::Id> isCritical;
vtkm::cont::ArrayHandle<vtkm::Id> outdegree;
inverseIndex.Allocate(nVertices);
isCritical.Allocate(nVertices);
outdegree.Allocate(nVertices);
cout << "SetSaddleStarts nVertices " << nVertices << endl;
vtkm::cont::ArrayHandleIndex vertexIndexArray(nVertices);
Mesh3D_DEM_VertexOutdegreeStarter<DeviceAdapter>
vertexOutdegreeStarter(nRows,
nCols,
nSlices,
ascending,
linkComponentCaseTable3D.PrepareForInput(device));
vtkm::worklet::DispatcherMapField<Mesh3D_DEM_VertexOutdegreeStarter<DeviceAdapter> >
vertexOutdegreeStarterDispatcher(vertexOutdegreeStarter);
vertexOutdegreeStarterDispatcher.Invoke(vertexIndexArray, // input
neighbourhoodMask, // input
mergeGraph.arcArray, // input (whole array)
outdegree, // output
isCritical); // output
DeviceAlgorithm::ScanExclusive(isCritical, inverseIndex);
// now we can compute how many critical points we carry forward
vtkm::Id nCriticalPoints = inverseIndex.GetPortalConstControl().Get(nVertices-1) +
isCritical.GetPortalConstControl().Get(nVertices-1);
cout << "SetSaddleStarts inverseIndex last vert " << inverseIndex.GetPortalConstControl().Get(nVertices-1) << endl;
cout << "SetSaddleStarts isCritical last vert " << isCritical.GetPortalConstControl().Get(nVertices-1) << endl;
cout << "SetSaddleStarts nCriticalPoints " << nCriticalPoints << endl;
// allocate space for the join graph vertex arrays
mergeGraph.AllocateVertexArrays(nCriticalPoints);
// compact the set of vertex indices to critical ones only
DeviceAlgorithm::StreamCompact(vertexIndexArray, isCritical, mergeGraph.valueIndex);
// we initialise the prunesTo array to "NONE"
vtkm::cont::ArrayHandleConstant<vtkm::Id> notAssigned(NO_VERTEX_ASSIGNED, nCriticalPoints);
DeviceAlgorithm::Copy(notAssigned, mergeGraph.prunesTo);
// copy the outdegree from our temporary array
// : mergeGraph.outdegree[vID] <= outdegree[mergeGraph.valueIndex[vID]]
DeviceAlgorithm::StreamCompact(outdegree, isCritical, mergeGraph.outdegree);
// copy the chain maximum from arcArray
// : mergeGraph.chainExtremum[vID] = inverseIndex[mergeGraph.arcArray[mergeGraph.valueIndex[vID]]]
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdArrayType;
typedef vtkm::cont::ArrayHandlePermutation<IdArrayType, IdArrayType> PermuteIndexType;
vtkm::cont::ArrayHandle<vtkm::Id> tArray;
tArray.Allocate(nCriticalPoints);
DeviceAlgorithm::StreamCompact(mergeGraph.arcArray, isCritical, tArray);
DeviceAlgorithm::Copy(PermuteIndexType(tArray, inverseIndex), mergeGraph.chainExtremum);
// and set up the active vertices - initially to identity
vtkm::cont::ArrayHandleIndex criticalVertsIndexArray(nCriticalPoints);
DeviceAlgorithm::Copy(criticalVertsIndexArray, mergeGraph.activeVertices);
// now we need to compute the firstEdge array from the outdegrees
DeviceAlgorithm::ScanExclusive(mergeGraph.outdegree, mergeGraph.firstEdge);
vtkm::Id nCriticalEdges = mergeGraph.firstEdge.GetPortalConstControl().Get(nCriticalPoints-1) +
mergeGraph.outdegree.GetPortalConstControl().Get(nCriticalPoints-1);
// now we allocate the edge arrays
mergeGraph.AllocateEdgeArrays(nCriticalEdges);
// and we have to set them, so we go back to the vertices
Mesh3D_DEM_SaddleStarter<DeviceAdapter>
saddleStarter(nRows, // input
nCols, // input
nSlices, // input
ascending, // input
linkComponentCaseTable3D.PrepareForInput(device));
vtkm::worklet::DispatcherMapField<Mesh3D_DEM_SaddleStarter<DeviceAdapter> >
saddleStarterDispatcher(saddleStarter);
vtkm::cont::ArrayHandleZip<vtkm::cont::ArrayHandle<vtkm::Id>, vtkm::cont::ArrayHandle<vtkm::Id> > outDegFirstEdge =
vtkm::cont::make_ArrayHandleZip(mergeGraph.outdegree, mergeGraph.firstEdge);
saddleStarterDispatcher.Invoke(criticalVertsIndexArray, // input
outDegFirstEdge, // input (pair)
mergeGraph.valueIndex, // input
neighbourhoodMask, // input (whole array)
mergeGraph.arcArray, // input (whole array)
inverseIndex, // input (whole array)
mergeGraph.edgeNear, // output (whole array)
mergeGraph.edgeFar, // output (whole array)
mergeGraph.activeEdges); // output (whole array)
// finally, allocate and initialise the edgeSorter array
DeviceAlgorithm::Copy(mergeGraph.activeEdges, mergeGraph.edgeSorter);
} // SetSaddleStarts()
}
}
}
#endif

@ -0,0 +1,58 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtkm_worklet_contourtree_mesh3d_dem_triangulation_macros_h
#define vtkm_worklet_contourtree_mesh3d_dem_triangulation_macros_h
// macro definitions
#define N_EDGE_TYPES 3
#define EDGE_TYPE_HORIZONTAL 0
#define EDGE_TYPE_VERTICAL 1
#define EDGE_TYPE_DIAGONAL 2
#define N_INCIDENT_EDGES_3D 14
#define MAX_OUTDEGREE_3D 6
// vertex row
#define VERTEX_ROW_3D(V,NROWS,NCOLS) (((V) % (NROWS * NCOLS)) / NCOLS)
// vertex column
#define VERTEX_COL_3D(V,NROWS,NCOLS) ((V) % (NCOLS))
// vertex slice
#define VERTEX_SLICE_3D(V,NROWS,NCOLS) ((V) / (NROWS * NCOLS))
// vertex ID - row * ncols + col
#define VERTEX_ID_3D(S,R,C,NROWS,NCOLS) (((S) * NROWS + (R)) * (NCOLS)+(C))
// edge row - edge / (ncols * nEdgeTypes)
#define EDGE_ROW(E,NCOLS) ((E)/((NCOLS)*(N_EDGE_TYPES)))
// edge col - (edge / nEdgeTypes) % nCols
#define EDGE_COL(E,NCOLS) (((E)/(N_EDGE_TYPES))%(NCOLS))
// edge which - edge % nEdgeTypes
#define EDGE_WHICH(E) ((E)%(N_EDGE_TYPES))
// edge ID - (row * ncols + col) * nEdgeTypes + which
#define EDGE_ID(R,C,W,NCOLS) ((((R)*(NCOLS)+(C))*(N_EDGE_TYPES))+(W))
// edge from - vertex with same row & col
#define EDGE_FROM(E,NCOLS) VERTEX_ID(EDGE_ROW(E,NCOLS),EDGE_COL(E,NCOLS),NCOLS)
// edge to - edge from +1 col if not vertical, +1 row if not horizontal
#define EDGE_TO(E,NCOLS) VERTEX_ID(EDGE_ROW(E,NCOLS)+((EDGE_WHICH(E)==EDGE_TYPE_HORIZONTAL)?0:1),EDGE_COL(E,NCOLS)+((EDGE_WHICH(E)==EDGE_TYPE_VERTICAL)?0:1),NCOLS)
#endif

@ -0,0 +1,171 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh2D_DEM_VertexOutdegreeStarter.h - computes how many unique starts per vertex
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh3d_dem_vertex_outdegree_starter_h
#define vtkm_worklet_contourtree_mesh3d_dem_vertex_outdegree_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_Triangulation_Macros.h>
#include <vtkm/worklet/contourtree/LinkComponentCaseTable3D.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
template<typename DeviceAdapter>
class Mesh3D_DEM_VertexOutdegreeStarter : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index into active vertices
FieldIn<IdType> nbrMask, // (input) neighbor mask
WholeArrayIn<IdType> arcArray, // (input) chain extrema
FieldOut<IdType> outdegree, // (output) outdegree
FieldOut<IdType> isCritical); // (output) whether critical
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
typedef _1 InputDomain;
typedef typename vtkm::cont::ArrayHandle<vtkm::UInt16>::template ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
IdPortalType caseTable; // (input) case table for neighbours
vtkm::Id nRows; // (input) number of rows in 3D
vtkm::Id nCols; // (input) number of cols in 3D
vtkm::Id nSlices; // (input) number of cols in 3D
bool ascending; // (input) ascending or descending (join or split tree)
const vtkm::IdComponent neighbourOffsets3D[N_INCIDENT_EDGES_3D][3] = {
{ -1, -1, -1 }, { 0, -1, 0 }, { -1, -1, 0 }, { -1, 0, 0 }, { -1, 0, -1 }, { 0, 0, -1 }, { 0, -1, -1 },
{ 0, 0, 1 }, { 0, 1, 0 }, { 0, 1, 1 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 }
};
// Constructor
VTKM_EXEC_CONT
Mesh3D_DEM_VertexOutdegreeStarter(vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices,
bool Ascending,
IdPortalType CaseTable) :
nRows(NRows),
nCols(NCols),
nSlices(NSlices),
ascending(Ascending),
caseTable(CaseTable) {}
//template<typename InFieldPortalType>
template<typename InFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const vtkm::Id& nbrMask,
const InFieldPortalType& arcArray,
vtkm::Id& outdegree,
vtkm::Id& isCritical) const
{
// get the row and column
vtkm::Id row = VERTEX_ROW_3D(vertex, nRows, nCols);
vtkm::Id col = VERTEX_COL_3D(vertex, nRows, nCols);
vtkm::Id slice = VERTEX_SLICE_3D(vertex, nRows, nCols);
// we know which edges are outbound, so we count to get the outdegree
vtkm::Id outDegree = 0;
vtkm::Id farEnds[MAX_OUTDEGREE_3D];
for (vtkm::Id edgeNo = 0; edgeNo < N_INCIDENT_EDGES_3D; edgeNo++)
{
if (caseTable.Get(nbrMask) & (1 << edgeNo))
{
vtkm::Id nbrSlice = slice + neighbourOffsets3D[edgeNo][0];
vtkm::Id nbrRow = row + neighbourOffsets3D[edgeNo][1];
vtkm::Id nbrCol = col + neighbourOffsets3D[edgeNo][2];
vtkm::Id nbr = VERTEX_ID_3D(nbrSlice, nbrRow, nbrCol, nRows, nCols);
farEnds[outDegree++] = arcArray.Get(nbr);
}
}
// now we check them against each other
if ((outDegree == 2) && (farEnds[0] == farEnds[1]))
{ // outDegree 2 & both match
// treat as a regular point
outDegree = 1;
} // outDegree 2 & both match
else if (outDegree == 3)
{ // outDegree 3
if (farEnds[0] == farEnds[1])
{ // first two match
if (farEnds[0] == farEnds[2])
{ // triple match
// all match - treat as regular point
outDegree = 1;
} // triple match
else
{ // first two match, but not third
// copy third down one place
farEnds[1] = farEnds[2];
// and reset the count
outDegree = 2;
} //
} // first two match
else if ((farEnds[0] == farEnds[2]) || (farEnds[1] == farEnds[2]))
{ // second one matches either of the first two
// decrease the count, keeping 0 & 1
outDegree = 2;
} // second one matches either of the first two
} // outDegree 3
// now store the outDegree
outdegree = outDegree;
// and set the initial inverse index to a flag
isCritical = (outDegree != 1) ? 1 : 0;
}
}; // Mesh3D_DEM_VertexOutdegreeStarter
} // namespace contourtree
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,244 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Mesh3D_DEM_VertexAscender.h - a functor that computes a link mask & a regular ascent
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop examining neighbours - again, for arbitrary
// meshes, it needs to be a reduction, but for regular meshes, it's faster this way.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_mesh3d_dem_vertex_starter_h
#define vtkm_worklet_contourtree_mesh3d_dem_vertex_starter_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Mesh3D_DEM_Triangulation_Macros.h>
#include <vtkm/worklet/contourtree/VertexValueComparator.h>
#include <iostream>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
template<typename T>
class Mesh3D_DEM_VertexStarter : public vtkm::worklet::WorkletMapField
{
public:
struct TagType : vtkm::ListTagBase<T> {};
typedef void ControlSignature(FieldIn<IdType> vertex, // (input) index of vertex
WholeArrayIn<TagType> values, // (input) values within mesh
FieldOut<IdType> chain, // (output) modify the chains
FieldOut<IdType> linkMask); // (output) modify the mask
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef _1 InputDomain;
vtkm::Id nRows; // (input) number of rows in 3D
vtkm::Id nCols; // (input) number of cols in 3D
vtkm::Id nSlices; // (input) number of cols in 3D
bool ascending; // ascending or descending (join or split tree)
// Constructor
VTKM_EXEC_CONT
Mesh3D_DEM_VertexStarter(vtkm::Id NRows,
vtkm::Id NCols,
vtkm::Id NSlices,
bool Ascending) : nRows(NRows),
nCols(NCols),
nSlices(NSlices),
ascending(Ascending) {}
// Locate the next vertex in direction indicated
template <typename InFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertex,
const InFieldPortalType& values,
vtkm::Id& chain,
vtkm::Id& linkMask) const
{
VertexValueComparator<InFieldPortalType> lessThan(values);
vtkm::Id row = VERTEX_ROW_3D(vertex, nRows, nCols);
vtkm::Id col = VERTEX_COL_3D(vertex, nRows, nCols);
vtkm::Id slice = VERTEX_SLICE_3D(vertex, nRows, nCols);
vtkm::Id destination = vertex;
vtkm::Id mask = 0;
bool isLeft = (col == 0);
bool isRight = (col == nCols - 1);
bool isTop = (row == 0);
bool isBottom = (row == nRows - 1);
bool isFront = (slice == 0);
bool isBack = (slice == nSlices - 1);
// This order of processing must be maintained to match the LinkComponentCaseTables
// and to return the correct destination extremum
for (vtkm::Id edgeNo = (N_INCIDENT_EDGES_3D - 1); edgeNo >= 0; edgeNo--)
{
vtkm::Id nbr;
switch (edgeNo)
{
////////////////////////////////////////////////////////
case 13: // down right back
if (isBack || isRight || isBottom) break;
nbr = vertex + (nRows * nCols) + nCols + 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x2000;
destination = nbr;
break;
case 12: // down back
if (isBack || isBottom) break;
nbr = vertex + (nRows * nCols) + nCols;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x1000;
destination = nbr;
break;
case 11: // right back
if (isBack || isRight) break;
nbr = vertex + (nRows * nCols) + 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x800;
destination = nbr;
break;
case 10: // back
if (isBack) break;
nbr = vertex + (nRows * nCols);
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x400;
destination = nbr;
break;
case 9: // down right
if (isBottom || isRight) break;
nbr = vertex + nCols + 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x200;
destination = nbr;
break;
case 8: // down
if (isBottom) break;
nbr = vertex + nCols;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x100;
destination = nbr;
break;
case 7: // right
if (isRight) break;
nbr = vertex + 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x80;
destination = nbr;
break;
case 6: // up left
if (isLeft || isTop) break;
nbr = vertex - nCols - 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x40;
destination = nbr;
break;
case 5: // left
if (isLeft) break;
nbr = vertex - 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x20;
destination = nbr;
break;
case 4: // left front
if (isLeft || isFront) break;
nbr = vertex - (nRows * nCols) - 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x10;
destination = nbr;
break;
case 3: // front
if (isFront) break;
nbr = vertex - (nRows * nCols);
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x08;
destination = nbr;
break;
case 2: // up front
if (isTop || isFront) break;
nbr = vertex - (nRows * nCols) - nCols;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x04;
destination = nbr;
break;
case 1: // up
if (isTop) break;
nbr = vertex - nCols;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x02;
destination = nbr;
break;
case 0: // up left front
if (isTop || isLeft || isFront) break;
nbr = vertex - (nRows * nCols) - nCols - 1;
if (lessThan(vertex, nbr, ascending)) break;
mask |= 0x01;
destination = nbr;
break;
} // switch on edgeNo
} // per edge
linkMask = mask;
chain = destination;
} // operator()
}; // Mesh3D_DEM_VertexStarter
}
}
}
#endif

@ -0,0 +1,202 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// PrintVectors.h - pretty printing (mostly for debug)
//
//=======================================================================================
//
// COMMENTS:
//
// Emphasis on robustness / simplicity rather than speed
//
//=======================================================================================
#ifndef vtkm_filter_print_vector
#define vtkm_filter_print_vector
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
using namespace std;
// debug value for number of columns to print
vtkm::Id printCols = 10;
#define PRINT_WIDTH 12
#define PREFIX_WIDTH 20
// debug value for number of columns to print
extern vtkm::Id printCols;
// utility routine to convert number to a string
string NumString(vtkm::Id number);
// base routines for printing label & prefix bars
void printLabel(string label);
void printSeparatingBar(vtkm::Id howMany);
// routines to print out a single value
template<typename T>
void printDataType(T value);
void printIndexType(vtkm::Id value);
// header line
void printHeader(vtkm::Id howMany);
// base routines for reading & writing host vectors
template<typename T, typename StorageType>
void printValues(string label, vtkm::cont::ArrayHandle<T,StorageType> &dVec, vtkm::Id nValues = -1);
void printIndices(string label, vtkm::cont::ArrayHandle<vtkm::Id> &iVec, vtkm::Id nIndices = -1);
// routines for printing indices & data in blocks
template<typename T, typename StorageType>
void printLabelledBlock(string label, const vtkm::cont::ArrayHandle<T, StorageType> &dVec, vtkm::Id nRows, vtkm::Id nColumns);
// utility routine to convert number to a string
string NumString(vtkm::Id number)
{ // NumString()
char strBuf[20];
sprintf(strBuf, "%1d", (int) number);
return string(strBuf);
} // NumString()
// base routines for printing label & prefix bars
void printLabel(string label)
{ // printLabel()
// print out the front end
cout << setw(PREFIX_WIDTH) << left << label;
// print out the vertical line
cout << right << "|";
} // printLabel()
void printSeparatingBar(vtkm::Id howMany)
{ // printSeparatingBar()
// print out the front end
cout << setw(PREFIX_WIDTH) << setfill('-') << "";
// now the + at the vertical line
cout << "+";
// now print out the tail end - fixed number of spaces per entry
for (vtkm::Id block = 0; block < howMany; block++)
cout << setw(PRINT_WIDTH) << setfill('-') << "";
// now the endl, resetting the fill character
cout << setfill(' ') << endl;
} // printSeparatingBar()
// routine to print out a single value
template<typename T>
void printDataType(T value)
{ // printDataType
cout << setw(PRINT_WIDTH) << value;
} // printDataType
// routine to print out a single value
void printIndexType(vtkm::Id value)
{ // printIndexType
cout << setw(PRINT_WIDTH) << value;
} // printIndexType
// header line
void printHeader(vtkm::Id howMany)
{ // printHeader()
if (howMany > 16) howMany = 16;
// print out a separating bar
printSeparatingBar(howMany);
// print out a label
printLabel("ID");
// print out the ID numbers
for (vtkm::Id entry = 0; entry < howMany; entry++)
printIndexType(entry);
// and an endl
cout << endl;
// print out another separating bar
printSeparatingBar(howMany);
} // printHeader()
// base routines for reading & writing host vectors
template<typename T, typename StorageType>
void printValues(string label, vtkm::cont::ArrayHandle<T,StorageType> &dVec, vtkm::Id nValues)
{
// -1 means full size
if (nValues == -1)
nValues = dVec.GetNumberOfValues();
if (nValues > 16) nValues = 16;
// print the label
printLabel(label);
// now print the data
for (vtkm::Id entry = 0; entry < nValues; entry++)
printDataType(dVec.GetPortalControl().Get(entry));
// and an endl
std::cout << std::endl;
} // printValues()
// base routines for reading & writing host vectors
void printIndices(string label, vtkm::cont::ArrayHandle<vtkm::Id> &iVec, vtkm::Id nIndices)
{
// -1 means full size
if (nIndices == -1)
nIndices = iVec.GetNumberOfValues();
if (nIndices > 16) nIndices = 16;
// print the label
printLabel(label);
// now print the data
for (vtkm::Id entry = 0; entry < nIndices; entry++)
printIndexType(iVec.GetPortalControl().Get(entry));
// and an endl
std::cout << std::endl;
} // printIndices()
template<typename T, typename StorageType>
void printLabelledBlock(string label, const vtkm::cont::ArrayHandle<T, StorageType> &dVec, vtkm::Id nRows, vtkm::Id nColumns)
{
// start with a header
printHeader(nColumns);
// loop control variable
vtkm::Id entry = 0;
// per row
for (vtkm::Id row = 0; row < nRows; row++)
{ // per row
printLabel(label + "[" + NumString(row) + "]");
// now print the data
for (vtkm::Id col = 0; col < nColumns; col++, entry++) {
printDataType(dVec.GetPortalConstControl().Get(entry));
}
cout << endl;
} // per row
cout << endl;
} // printLabelledBlock()
#endif

@ -0,0 +1,118 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// RegularPointTransferrer.h - iterator for transferring regular points
//
//=======================================================================================
//
// COMMENTS:
//
// This functor replaces a parallel loop through regular points, since more than one
// output needs to be set.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_regular_point_transferrer_h
#define vtkm_worklet_contourtree_regular_point_transferrer_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include "vtkm/worklet/contourtree/Mesh2D_DEM_Triangulation_Macros.h"
#include "vtkm/worklet/contourtree/VertexValueComparator.h"
#include "vtkm/worklet/contourtree/Types.h"
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
template<typename T>
class RegularPointTransferrer : public vtkm::worklet::WorkletMapField
{
public:
struct TagType : vtkm::ListTagBase<T> {};
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) vertex ID
WholeArrayIn<IdType> chainExtremum, // (input) chain extremum
WholeArrayIn<TagType> values, // (input) values array
WholeArrayIn<IdType> valueIndex, // (input) index into value array
WholeArrayInOut<IdType> prunesTo, // (i/o) where vertex is pruned to
WholeArrayOut<IdType> outdegree); // (output) updegree of vertex
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
bool isJoinGraph;
// Constructor
VTKM_EXEC_CONT
RegularPointTransferrer(bool IsJoinGraph) : isJoinGraph(IsJoinGraph) {}
template <typename InFieldPortalType, typename InIndexPortalType, typename InOutFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertexID,
const InIndexPortalType& chainExtremum,
const InFieldPortalType &values,
const InIndexPortalType &valueIndex,
const InOutFieldPortalType &prunesTo,
const OutFieldPortalType &outdegree) const
{
VertexValueComparator<InFieldPortalType> lessThan(values);
// ignore vertices which have already been labelled
vtkm::Id saddleID = prunesTo.Get(vertexID);
if (saddleID != NO_VERTEX_ASSIGNED)
return;
// now, if the vertex is beyond the governing saddle, we need to label it
// and arrange to get rid of it
saddleID = prunesTo.Get(chainExtremum.Get(vertexID));
if (lessThan(valueIndex.Get(saddleID), valueIndex.Get(vertexID), !isJoinGraph))
{
// set the merge extremum to the current chain extremum
prunesTo.Set(vertexID, chainExtremum.Get(vertexID));
// and reset the outdegree to zero
outdegree.Set(vertexID, 0);
} // regular point to be pruned
}
}; // RegularPointTransferrer
}
}
}
#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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// RegularToCritical.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_regular_to_candidate_h
#define vtkm_worklet_contourtree_regular_to_candidate_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include "vtkm/worklet/contourtree/Types.h"
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class RegularToCandidate : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexId, // (input) vertex id of candidate
WholeArrayIn<IdType> mergeArcs, // (input) merge arcs
WholeArrayIn<IdType> regularToCritical, // (input) sorting indices
FieldOut<IdType> sortVector); // (output) target for write back
typedef _4 ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
RegularToCandidate() {}
template <typename InFieldPortalType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id& vertexID,
const InFieldPortalType& mergeArcs,
const InFieldPortalType& regularToCritical) const
{
vtkm::Id sortVector;
// copy the mergeArc ID
vtkm::Id joinNeighbour = mergeArcs.Get(vertexID);
// if it's the root vertex
if (joinNeighbour == NO_VERTEX_ASSIGNED)
// set it to the sentinel value
sortVector = NO_VERTEX_ASSIGNED;
else
// otherwise convert to a candidate ID & save
sortVector = regularToCritical.Get(joinNeighbour);
return sortVector;
}
}; // RegularToCandidate
}
}
}
#endif

@ -0,0 +1,89 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// RegularToCriticalDown.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_regular_to_critical_down_h
#define vtkm_worklet_contourtree_regular_to_critical_down_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to critical
class RegularToCriticalDown : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) candidate index
WholeArrayIn<IdType> mergeArcs, // (input) merge arcs
WholeArrayIn<IdType> regularToCritical, // (input)
FieldOut<IdType> sortVector); // (output)
typedef _4 ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
RegularToCriticalDown() {}
template <typename InFieldPortalType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id& vertexID,
const InFieldPortalType& mergeArcs,
const InFieldPortalType& regularToCritical) const
{
vtkm::Id sortVector;
// copy the mergeArc ID
vtkm::Id splitNeighbour = mergeArcs.Get(vertexID);
// if it's the root vertex
if (splitNeighbour == NO_VERTEX_ASSIGNED)
// set it to the sentinel value
sortVector = NO_VERTEX_ASSIGNED;
else
// otherwise convert to a candidate ID & save
sortVector = regularToCritical.Get(splitNeighbour);
return sortVector;
}
}; // RegularToCriticalDown
}
}
}
#endif

@ -0,0 +1,76 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// RegularToCriticalUp.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_regular_to_critical_up_h
#define vtkm_worklet_contourtree_regular_to_critical_up_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to critical
class RegularToCriticalUp : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> candIndex, // (input) index into candidates
FieldIn<IdType> candidate, // (input) candidate index
WholeArrayOut<IdType> critical); // (output)
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
RegularToCriticalUp() {}
template <typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& index,
const vtkm::Id& candidate,
const OutFieldPortalType& critical) const
{
critical.Set(candidate, index);
}
}; // RegularToCriticalUp
}
}
}
#endif

@ -0,0 +1,77 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// ResetDegrees.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_reset_degrees_h
#define vtkm_worklet_contourtree_reset_degrees_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class ResetDegrees : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // input
WholeArrayOut<IdType> updegree, // output
WholeArrayOut<IdType> downdegree); // output
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
ResetDegrees() {}
template <typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& superId,
const OutFieldPortalType& updegree,
const OutFieldPortalType& downdegree) const
{
updegree.Set(superId, 0);
downdegree.Set(superId, 0);
}
}; // ResetDegrees
}
}
}
#endif

@ -0,0 +1,99 @@
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SaddleAscentFunctor.h - functor that counts & identifies active saddle edges
//
//=======================================================================================
//
// COMMENTS:
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_saddle_ascent_functor_h
#define vtkm_worklet_contourtree_saddle_ascent_functor_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class SaddleAscentFunctor : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) index into active vertices
WholeArrayIn<IdType> firstEdge, // (input) first edge for each active vertex
WholeArrayIn<IdType> outdegree, // (input) updegree of vertex
WholeArrayIn<IdType> activeEdges, // (input) active edges
WholeArrayIn<IdType> chainExtemum, // (input) chain extemum for vertices
WholeArrayInOut<IdType> edgeFar, // (input) high ends of edges
FieldOut<IdType> newOutdegree); // (output) new updegree of vertex
typedef _7 ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SaddleAscentFunctor() {}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id& vertexID,
const InFieldPortalType& firstEdge,
const InFieldPortalType& outdegree,
const InFieldPortalType& activeEdges,
const InFieldPortalType& chainExtremum,
const InOutFieldPortalType& edgeFar) const
{
vtkm::Id newOutdegree;
// first ascent found
vtkm::Id firstMax = NO_VERTEX_ASSIGNED;
bool isGenuineSaddle = false;
// loop through edges
for (vtkm::Id edge = 0; edge < outdegree.Get(vertexID); edge++)
{
// retrieve the edge ID and the high end of the edge
vtkm::Id edgeID = activeEdges.Get(firstEdge.Get(vertexID) + edge);
vtkm::Id nbrHigh = chainExtremum.Get(edgeFar.Get(edgeID));
edgeFar.Set(edgeID, nbrHigh);
// test for first one found
if (firstMax == NO_VERTEX_ASSIGNED)
firstMax = nbrHigh;
else // otherwise, check for whether we have an actual join saddle
if (firstMax != nbrHigh)
{ // first non-matching
isGenuineSaddle = true;
} // first non-matching
} // per edge
// if it's not a genuine saddle, ignore the edges by setting updegree to 0
if (!isGenuineSaddle)
newOutdegree = 0;
else
newOutdegree = outdegree.Get(vertexID);
return newOutdegree;
}
}; // SaddleAscentFunctor
}
}
}
#endif

@ -0,0 +1,98 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SaddleAscentTransferrer.h - functor that transfers active saddle edges
//
//=======================================================================================
//
// COMMENTS:
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_saddle_ascent_transferrer_h
#define vtkm_worklet_contourtree_saddle_ascent_transferrer_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class SaddleAscentTransferrer : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) active vertex
FieldIn<IdType> newOutdegree, // (input) updated updegree
FieldIn<IdType> newFirstEdge, // (input) updated first edge of vertex
WholeArrayIn<IdType> activeEdges, // (input) active edges
WholeArrayIn<IdType> firstEdge, // (input) first edges
WholeArrayOut<IdType> edgeSorter); // (output) edge sorter
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SaddleAscentTransferrer() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertexID,
const vtkm::Id& newOutdegree,
const vtkm::Id& newFirstEdge,
const InFieldPortalType& activeEdges,
const InFieldPortalType& firstEdge,
const OutFieldPortalType& edgeSorter) const
{
// loop through the edges from the vertex
for (vtkm::Id edge = 0; edge < newOutdegree; edge++)
{
// compute which index in the new sorting array
vtkm::Id edgeSorterIndex = newFirstEdge + edge;
// now retrieve the old edge
vtkm::Id edgeID = activeEdges.Get(firstEdge.Get(vertexID) + edge);
// adding them to the edge sort array
edgeSorter.Set(edgeSorterIndex, edgeID);
}
}
}; // SaddleAscentTransferrer
}
}
}
#endif

@ -0,0 +1,96 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SetJoinAndSplitArcs.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_set_join_and_split_arcs_h
#define vtkm_worklet_contourtree_set_join_and_split_arcs_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class SetJoinAndSplitArcs : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> regularID, // (input)
WholeArrayIn<IdType> joinMergeArcs, // (input)
WholeArrayIn<IdType> splitMergeArcs, // (input)
WholeArrayIn<IdType> regularToCritical, // (input)
FieldOut<IdType> joinArc, // (output)
FieldOut<IdType> splitArc); // (output)
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SetJoinAndSplitArcs() {}
template <typename InFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& regularID,
const InFieldPortalType& joinMergeArcs,
const InFieldPortalType& splitMergeArcs,
const InFieldPortalType& regularToCritical,
vtkm::Id &joinArc,
vtkm::Id &splitArc) const
{
// use it to grab join arc target
vtkm::Id joinTo = joinMergeArcs.Get(regularID);
// and set the join arc
if (joinTo == NO_VERTEX_ASSIGNED)
joinArc = NO_VERTEX_ASSIGNED;
else
joinArc = regularToCritical.Get(joinTo);
// now grab split arc target
vtkm::Id splitTo = splitMergeArcs.Get(regularID);
// and set the split arc
if (splitTo == NO_VERTEX_ASSIGNED)
splitArc = NO_VERTEX_ASSIGNED;
else
splitArc = regularToCritical.Get(splitTo);
}
}; // SetJoinAndSplitArcs
}
}
}
#endif

@ -0,0 +1,98 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SetSupernodeInward.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_set_supernode_inward_h
#define vtkm_worklet_contourtree_set_supernode_inward_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class SetSupernodeInward : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // (input) index into supernodes
WholeArrayIn<IdType> inbound, // (input) join or split arc
WholeArrayIn<IdType> outbound, // (input) join or split arc
WholeArrayIn<IdType> indegree, // (input)
WholeArrayIn<IdType> outdegree, // (input)
WholeArrayInOut<IdType> superarcs); // (in out)
typedef void ExecutionSignature(_1, _2, _3, _4, _5, _6);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SetSupernodeInward() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& superID,
const InFieldPortalType& inbound,
const InFieldPortalType& outbound,
const InFieldPortalType& indegree,
const InFieldPortalType& outdegree,
const OutFieldPortalType& superarcs) const
{
// test for criticality
vtkm::Id outNeighbour = outbound.Get(superID);
vtkm::Id inNeighbour = inbound.Get(superID);
if (outNeighbour == NO_VERTEX_ASSIGNED)
return;
// test for leaf-ness
if ((outdegree.Get(outNeighbour) != 0) || (indegree.Get(outNeighbour) != 1))
return;
// skip if the superarc is already set
if (superarcs.Get(superID) != NO_VERTEX_ASSIGNED)
return;
// we've passed the tests - set the supernode to point inwards
superarcs.Set(superID, inNeighbour);
}
}; // SetSupernodeInward
}
}
}
#endif

@ -0,0 +1,93 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SkipVertex.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_skip_vertex_h
#define vtkm_worklet_contourtree_skip_vertex_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class SkipVertex : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // (input) index into supernodes
WholeArrayIn<IdType> superarcs, // (input)
WholeArrayInOut<IdType> joinArcs, // (i/o)
WholeArrayInOut<IdType> splitArcs); // (i/o)
typedef void ExecutionSignature(_1, _2, _3, _4);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SkipVertex() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& superID,
const InFieldPortalType& superarcs,
const OutFieldPortalType& joinArcs,
const OutFieldPortalType& splitArcs) const
{
// retrieve it's join neighbour j
vtkm::Id joinNeighbour = joinArcs.Get(superID);
// if v has a join neighbour (i.e. j == -1) and j has a contour arc
if ((joinNeighbour != NO_VERTEX_ASSIGNED) && (superarcs.Get(joinNeighbour) != NO_VERTEX_ASSIGNED))
// reset the vertex' join neighbour
joinArcs.Set(superID, joinArcs.Get(joinNeighbour));
// retrieve it's split neighbour s
vtkm::Id splitNeighbour = splitArcs.Get(superID);
// if v has a split neighbour (i.e. s == -1) and s has a contour arc
if ((splitNeighbour != NO_VERTEX_ASSIGNED) && (superarcs.Get(splitNeighbour) != NO_VERTEX_ASSIGNED))
// reset the vertex' split neighbour
splitArcs.Set(superID, splitArcs.Get(splitNeighbour));
}
}; // SkipVertex
}
}
}
#endif

@ -0,0 +1,77 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// SubrangeOffset.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_subrange_offset_h
#define vtkm_worklet_contourtree_subrange_offset_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class SubrangeOffset : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> sortID, // (input) index into sorted vertices
WholeArrayIn<IdType> sortVector, // (input) sorted vector of vertices
WholeArrayOut<IdType> candidate); // (output) candidate
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
SubrangeOffset() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& sortID,
const InFieldPortalType& sortVector,
const OutFieldPortalType& candidate) const
{
if (sortVector.Get(sortID) != sortVector.Get(sortID-1))
candidate.Set(sortVector.Get(sortID), sortID);
}
}; // SubrangeOffset
}
}
}
#endif

@ -0,0 +1,92 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// TrunkBuilder.h - functor that sets remaining active vertices to the trunk
//
//=======================================================================================
//
// COMMENTS:
//
// This functor is applied to all remaining active vertices. The remaining maximum is the
// chain maximum of all vertices, and is set to prune to NO_VERTEX_ASSIGNED (the global
// root). All others are set to prune to it.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_trunk_builder_h
#define vtkm_worklet_contourtree_trunk_builder_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class TrunkBuilder : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) index into active vertices
WholeArrayIn<IdType> chainExtremum, // (input) chain extemum for vertices
WholeArrayOut<IdType> prunesTo); // (output) where a vertex prunes to
typedef void ExecutionSignature(_1, _2, _3);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
TrunkBuilder() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
void operator()(const vtkm::Id& vertexID,
const InFieldPortalType& chainExtremum,
const OutFieldPortalType& prunesTo) const
{
// the chain max of everyone prunes to the global minimum
vtkm::Id chainExt = chainExtremum.Get(vertexID);
if (vertexID == chainExt)
prunesTo.Set(vertexID, NO_VERTEX_ASSIGNED);
else
prunesTo.Set(vertexID, chainExt);
}
}; // TrunkBuilder
}
}
}
#endif

@ -0,0 +1,33 @@
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// Type.h - simple include to define types
//
//=======================================================================================
//
// COMMENTS:
//
// We may end up templating later if this works, but we'll probably do a major rewrite
// in that case anyway. Instead, we will define two basic types:
//
// dataType: the underlying type of the data being processed
// indexType: the type required for indices - should normally be signed, so we can
// use negative deltas in a couple of places
//
// Part of the reason for this is that we expect to migrate to 64-bit indices later
// and it would be awkward to have to go back and rewrite
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_types_h
#define vtkm_worklet_contourtree_types_h
// constant for consistent processing
#define NO_VERTEX_ASSIGNED -1
#endif

@ -0,0 +1,87 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// CopyJoinSplit.h - functor that performs conditional chain-doubling
//
//=======================================================================================
//
// COMMENTS:
//
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_update_outbound_h
#define vtkm_worklet_contourtree_update_outbound_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
#include <vtkm/worklet/contourtree/Types.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for doing regular to candidate
class UpdateOutbound : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> superID, // input
WholeArrayInOut<IdType> outbound); // i/o
typedef void ExecutionSignature(_1, _2);
typedef _1 InputDomain;
// Constructor
VTKM_EXEC_CONT
UpdateOutbound() {}
template <typename InOutPortalType>
VTKM_EXEC
void operator()(const vtkm::Id &superID,
const InOutPortalType& outbound) const
{
vtkm::Id outNeighbour = outbound.Get(superID);
// ignore if it has no out neighbour
if (outNeighbour == NO_VERTEX_ASSIGNED)
return;
// if it's out neighbour has none itself, it's a critical point & we stop
vtkm::Id doubleOut = outbound.Get(outNeighbour);
if (doubleOut == NO_VERTEX_ASSIGNED)
return;
// otherwise, we update
outbound.Set(superID, doubleOut);
}
}; // UpdateOutbound
}
}
}
#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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// VertexDegreeUpdater.h - functor that computes modified updegree for vertex in graph
//
//=======================================================================================
//
// COMMENTS:
//
// This functor identifies for each vertex which edges to keep. For arbitrary meshes,
// this should use reductions. For regular meshes, this way is faster due to low bounded
// updegree.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
// Vectors marked I/O are intrinsically risky unless there is an algorithmic guarantee
// that the read/writes are completely independent - which for our case actually occurs
// The I/O vectors should therefore be justified in comments both here & in caller
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_vertex_degree_updater_h
#define vtkm_worklet_contourtree_vertex_degree_updater_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ExecutionWholeArray.h>
namespace vtkm {
namespace worklet {
namespace contourtree {
// Worklet for setting initial chain maximum value
class VertexDegreeUpdater : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexID, // (input) active vertices
WholeArrayIn<IdType> activeEdges, // (input) active edges
WholeArrayIn<IdType> edgeFar, // (input) high ends of edges
WholeArrayIn<IdType> firstEdge, // (input) first edge for each active vertex
WholeArrayIn<IdType> prunesTo, // (input) where vertex is pruned to
WholeArrayIn<IdType> outdegree, // (input) updegree of vertex
WholeArrayInOut<IdType> chainExtemum, // (i/o) chain extemum for vertices
FieldOut<IdType> newOutdegree); // (output) new updegree of vertex
typedef _8 ExecutionSignature(_1, _2, _3, _4, _5, _6, _7);
typedef _1 InputDomain;
// chainMaximum is safe for I/O here because:
// we have previously eliminated maxima from the active vertex list
// our lookup uses the chainMaximum of the edgeHigh, which is guaranteed to
// be a maximum
// therefore, the chainMaximum entries edited are *NEVER* also accessed & v.v.
// Constructor
VTKM_EXEC_CONT
VertexDegreeUpdater() {}
template <typename InFieldPortalType, typename OutFieldPortalType>
VTKM_EXEC
vtkm::Id operator()(const vtkm::Id &vertexID,
const InFieldPortalType &activeEdges,
const InFieldPortalType &edgeFar,
const InFieldPortalType &firstEdge,
const InFieldPortalType &prunesTo,
const InFieldPortalType &outdegree,
const OutFieldPortalType &chainExtremum) const
{
vtkm::Id newOutdegree = 0;
// retrieve actual vertex ID & first edge
vtkm::Id edgeFirst = firstEdge.Get(vertexID);
// also reset the chain maximum to the vertex' ID
chainExtremum.Set(vertexID, vertexID);
// walk through the vertex' edges
for (vtkm::Id edge = 0; edge < outdegree.Get(vertexID); edge++)
{
vtkm::Id edgeIndex = edgeFirst + edge;
vtkm::Id edgeID = activeEdges.Get(edgeIndex);
// retrieve the vertex ID for the high end & update for pruning
vtkm::Id highEnd = prunesTo.Get(chainExtremum.Get(edgeFar.Get(edgeID)));
// we want to ignore edges that lead back to this vertex
if (highEnd == vertexID)
continue;
// if we survived, increment the outdegree
newOutdegree++;
} // per edge
return newOutdegree;
}
}; // VertexDegreeUpdater
}
}
}
#endif

@ -0,0 +1,108 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// joinArcFunctor.cpp - functors for the thrust version of JoinTree.cpp
//
//=======================================================================================
//
// COMMENTS:
//
// Basically, we have a single functor (so far), whose job is to work out the downwards
// join neighbour of each vertex.
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_vertex_merge_comparator_h
#define vtkm_worklet_contourtree_vertex_merge_comparator_h
namespace vtkm {
namespace worklet {
namespace contourtree {
//=======================================================================================
//
// VertexMergeComparator
//
// A comparator that sorts the vertices on the join maximum (assuming already sorted on
// indexed value)
//
//=======================================================================================
template <typename T, typename StorageType, typename DeviceAdapter>
class VertexMergeComparator
{
public:
typedef typename vtkm::cont::ArrayHandle<T,StorageType>::template ExecutionTypes<DeviceAdapter>::PortalConst ValuePortalType;
typedef typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
ValuePortalType values;
IdPortalType extrema;
bool isJoinTree;
VTKM_CONT
VertexMergeComparator(ValuePortalType Values,
IdPortalType Extrema,
bool IsJoinTree)
: values(Values), extrema(Extrema), isJoinTree(IsJoinTree)
{}
VTKM_EXEC_CONT
bool operator() (const vtkm::Id& i, const vtkm::Id& j) const
{
// retrieve the pseudo-extremum the vertex belongs to
vtkm::Id pseudoExtI = extrema.Get(i);
vtkm::Id pseudoExtJ = extrema.Get(j);
if (pseudoExtI < pseudoExtJ)
return false ^ isJoinTree;
if (pseudoExtJ < pseudoExtI)
return true ^ isJoinTree;
T valueI = values.Get(i);
T valueJ = values.Get(j);
if (valueI < valueJ)
return false ^ isJoinTree;
if (valueI > valueJ)
return true ^ isJoinTree;
if (i < j)
return false ^ isJoinTree;
if (j < i)
return true ^ isJoinTree;
return false; // true ^ isJoinTree;
}
}; // VertexMergeComparator
}
}
}
#endif

@ -0,0 +1,79 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
//=======================================================================================
//
// Second Attempt to Compute Contour Tree in Data-Parallel Mode
//
// Started August 19, 2015
//
// Copyright Hamish Carr, University of Leeds
//
// VertexValueComparator.h - a comparator for sorting the original array
//
//=======================================================================================
//
// COMMENTS:
//
// A comparator that sorts vertices by data value, falling back on index to implement
// simulation of simplicity
//
// Any vector needed by the functor for lookup purposes will be passed as a parameter to
// the constructor and saved, with the actual function call being the operator ()
//
//=======================================================================================
#ifndef vtkm_worklet_contourtree_vertex_value_comparator_h
#define vtkm_worklet_contourtree_vertex_value_comparator_h
namespace vtkm {
namespace worklet {
namespace contourtree {
template <typename InFieldPortalType>
class VertexValueComparator
{
public:
const InFieldPortalType& values;
VTKM_CONT
VertexValueComparator(const InFieldPortalType& Values) : values(Values) {}
VTKM_EXEC_CONT
bool operator () (const vtkm::Id &i, const vtkm::Id &j, bool ascending)
{
if (values.Get(i) < values.Get(j))
return ascending ^ true;
else if (values.Get(j) < values.Get(i))
return ascending ^ false;
else if (i < j)
return ascending ^ true;
else if (j < i)
return ascending ^ false;
// fall through to return false
return false;
}
};
}
}
}
#endif

@ -23,6 +23,7 @@ set(unit_tests
UnitTestCellDeepCopy.cxx
UnitTestCellGradient.cxx
UnitTestClipping.cxx
UnitTestContourTreeUniform.cxx
UnitTestExternalFaces.cxx
UnitTestFieldHistogram.cxx
UnitTestFieldStatistics.cxx

@ -0,0 +1,195 @@
//============================================================================
// 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 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#include <vtkm/worklet/ContourTreeUniform.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/testing/Testing.h>
//
// Test 2D regular dataset
//
vtkm::cont::DataSet MakeContourTreeMesh2DTestDataSet()
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id2 dimensions(5,5);
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::DataSetFieldAdd dsf;
const vtkm::Id nVerts = 25;
vtkm::Float32 var[nVerts] = {
100.0f, 78.0f, 49.0f, 17.0f, 1.0f,
94.0f, 71.0f, 47.0f, 33.0f, 6.0f,
52.0f, 44.0f, 50.0f, 45.0f, 48.0f,
8.0f, 12.0f, 46.0f, 91.0f, 43.0f,
0.0f, 5.0f, 51.0f, 76.0f, 83.0f};
dsf.AddPointField(dataSet, "values", var, nVerts);
return dataSet;
}
//
// Create a uniform 2D structured cell set as input with values for contours
//
void TestContourTree_Mesh2D_DEM_Triangulation()
{
std::cout << "Testing ContourTree_Mesh2D Filter" << std::endl;
// Create the input uniform cell set with values to contour
vtkm::cont::DataSet dataSet = MakeContourTreeMesh2DTestDataSet();
vtkm::cont::CellSetStructured<2> cellSet;
dataSet.GetCellSet().CopyTo(cellSet);
vtkm::Id2 pointDimensions = cellSet.GetPointDimensions();
vtkm::Id nRows = pointDimensions[0];
vtkm::Id nCols = pointDimensions[1];
vtkm::cont::ArrayHandle<vtkm::Float32> fieldArray;
dataSet.GetField("values").GetData().CopyTo(fieldArray);
// Output saddle peak pairs array
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
// Create the worklet and run it
vtkm::worklet::ContourTreeMesh2D contourTreeMesh2D;
contourTreeMesh2D.Run(fieldArray,
nRows,
nCols,
saddlePeak,
DeviceAdapter());
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetNumberOfValues(), 7), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(0), vtkm::make_Pair( 0, 12)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(1), vtkm::make_Pair( 4, 13)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(2), vtkm::make_Pair(12, 13)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(3), vtkm::make_Pair(12, 18)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(4), vtkm::make_Pair(12, 20)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(5), vtkm::make_Pair(13, 14)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(6), vtkm::make_Pair(13, 19)), "Wrong result for ContourTree filter");
}
//
// Test 3D regular dataset
//
vtkm::cont::DataSet MakeContourTreeMesh3DTestDataSet()
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id3 dimensions(5,5,5);
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::DataSetFieldAdd dsf;
const vtkm::Id nVerts = 125;
vtkm::Float32 var[nVerts] = {
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 99.0f, 90.0f, 85.0f, 0.0f,
0.0f, 95.0f, 80.0f, 95.0f, 0.0f,
0.0f, 85.0f, 90.0f, 99.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 75.0f, 50.0f, 65.0f, 0.0f,
0.0f, 55.0f, 15.0f, 45.0f, 0.0f,
0.0f, 60.0f, 40.0f, 70.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 97.0f, 87.0f, 82.0f, 0.0f,
0.0f, 92.0f, 77.0f, 92.0f, 0.0f,
0.0f, 82.0f, 87.0f, 97.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
dsf.AddPointField(dataSet, "values", var, nVerts);
return dataSet;
}
//
// Create a uniform 3D structured cell set as input with values for contours
//
void TestContourTree_Mesh3D_DEM_Triangulation()
{
std::cout << "Testing ContourTree_Mesh3D Filter" << std::endl;
// Create the input uniform cell set with values to contour
vtkm::cont::DataSet dataSet = MakeContourTreeMesh3DTestDataSet();
vtkm::cont::CellSetStructured<3> cellSet;
dataSet.GetCellSet().CopyTo(cellSet);
vtkm::Id3 pointDimensions = cellSet.GetPointDimensions();
vtkm::Id nRows = pointDimensions[0];
vtkm::Id nCols = pointDimensions[1];
vtkm::Id nSlices = pointDimensions[2];
vtkm::cont::ArrayHandle<vtkm::Float32> fieldArray;
dataSet.GetField("values").GetData().CopyTo(fieldArray);
// Output saddle peak pairs array
vtkm::cont::ArrayHandle<vtkm::Pair<vtkm::Id, vtkm::Id> > saddlePeak;
// Create the worklet and run it
vtkm::worklet::ContourTreeMesh3D contourTreeMesh3D;
contourTreeMesh3D.Run(fieldArray,
nRows,
nCols,
nSlices,
saddlePeak,
DeviceAdapter());
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetNumberOfValues(), 9), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(0), vtkm::make_Pair( 0, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(1), vtkm::make_Pair(31, 42)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(2), vtkm::make_Pair(42, 43)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(3), vtkm::make_Pair(42, 56)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(4), vtkm::make_Pair(56, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(5), vtkm::make_Pair(56, 92)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(6), vtkm::make_Pair(62, 67)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(7), vtkm::make_Pair(81, 92)), "Wrong result for ContourTree filter");
VTKM_TEST_ASSERT(test_equal(saddlePeak.GetPortalControl().Get(8), vtkm::make_Pair(92, 93)), "Wrong result for ContourTree filter");
}
void TestContourTreeUniform()
{
TestContourTree_Mesh2D_DEM_Triangulation();
TestContourTree_Mesh3D_DEM_Triangulation();
}
int UnitTestContourTreeUniform(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestContourTreeUniform);
}