Connected component for triangle mesh

This commit is contained in:
Li-Ta Lo 2017-12-22 10:31:02 -07:00
parent 8be1a71ada
commit 2e88f4220a
14 changed files with 1213 additions and 49 deletions

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

@ -0,0 +1,153 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <algorithm>
#include <iostream>
#include <random>
#include <vtkm/Math.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/worklet/DispatcherPointNeighborhood.h>
#include <vtkm/worklet/WorkletPointNeighborhood.h>
#include <vtkm/cont/TryExecute.h>
//#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
//#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
void populate(std::vector<vtkm::Float32>& pixels,
std::vector<vtkm::Id>& components,
vtkm::UInt32 width,
vtkm::UInt32 height)
{
for (auto& pixel : pixels) {
pixel = 0.0f;
}
for (int i = 6; i <= 8; i++) {
pixels[i] = 1.0f;
}
for (int i = 16; i <= 18; i++) {
pixels[i] = 1.0f;
}
for (int i = 0; i < width*height; ++i) {
components[i] = i;
}
}
struct UpdateComponent : public vtkm::worklet::WorkletPointNeighborhood3x3x3
{
typedef void ControlSignature(FieldInNeighborhood<Scalar> pixel,
CellSetIn,
FieldInNeighborhood<IdType> prevComponent,
FieldOut<IdType> component);
typedef void ExecutionSignature(_1, _3, _4);
//verify input domain can be something other than first parameter
typedef _2 InputDomain;
template <typename FieldIn, typename FieldIn1, typename FieldOut>
VTKM_EXEC void operator()(const vtkm::exec::arg::Neighborhood<1, FieldIn>& pixel,
const vtkm::exec::arg::Neighborhood<1, FieldIn1>& prevComponent,
FieldOut& component) const
//FieldIn1& component) const
{
//vtkm::UInt8 color =
std::cout << "pixel: " << pixel.Get(0, 0, 0)
<< ", component: " << prevComponent.Get(0, 0, 0)
<< std::endl;
vtkm::Float32 color = pixel.Get(0, 0, 0);
if (color == pixel.Get(-1, 0, 0)) {
component = prevComponent.Get(-1, 0, 0);
} else if (color == pixel.Get(0, -1, 0)) {
component = prevComponent.Get(0, -1, 0);
} else {
component = prevComponent.Get(0, 0, 0);
}
}
};
struct FindRoot : public vtkm::worklet::WorkletMapField
{
typedef void ControlSignature(FieldIn<IdType>,
WholeArrayInOut<IdType> component);
typedef void ExecutionSignature(_1, _2);
typedef _1 Inputdomain;
template <typename FieldIn, typename FieldOut>
VTKM_EXEC void operator()(const FieldIn& id, FieldOut& component) const {
//while (id != component.Get(id)) {
// if (id != component.Get(id)) {
// std::cout << "id: " << id << ", component: " << component.Get(id) << std::endl;
// component.Set(id, this->operator()(component.Get(id), component));
// }
vtkm::Id parent = component.Get(id);
while (parent != component.Get(parent)) {
parent = component.Get(parent);
component.Set(id, parent);
std::cout << "id: " << id << ", component: " << component.Get(id) << std::endl;
}
};
};
int main(int argc, char *argv[])
{
vtkm::cont::DataSetBuilderUniform builder;
vtkm::cont::DataSet data = builder.Create(vtkm::Id2(5, 5));
std::vector<vtkm::Float32> pixels(5*5);
std::vector<vtkm::Id> components(5*5);
populate(pixels, components, 5, 5);
vtkm::cont::Field pixelField("pixels", vtkm::cont::Field::ASSOC_POINTS, pixels);
data.AddField(pixelField);
vtkm::cont::Field componentField("components", vtkm::cont::Field::ASSOC_POINTS, components);
data.AddField(componentField);
vtkm::worklet::DispatcherPointNeighborhood<UpdateComponent> dispatcher;
vtkm::cont::ArrayHandle<vtkm::Id> output;
dispatcher.Invoke(data.GetField("pixels"),
data.GetCellSet(),
data.GetField("components"),
output);
for (int i = 0; i < output.GetNumberOfValues(); i++) {
std::cout << output.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
vtkm::worklet::DispatcherMapField<FindRoot> findRootDispatcher;
findRootDispatcher.Invoke(data.GetField("components"), output);
for (int i = 0; i < output.GetNumberOfValues(); i++) {
std::cout << output.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
}

@ -0,0 +1,7 @@
find_package(VTKm REQUIRED QUIET
OPTIONAL_COMPONENTS Serial #CUDA TBB OpenGL GLUT
)
add_executable(CCL CCL.cpp)
target_link_libraries(CCL PRIVATE ${VTKm_LIBRARIES})
target_compile_options(CCL PRIVATE ${VTKm_COMPILE_OPTIONS})

@ -20,7 +20,7 @@
##
##=============================================================================
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
#cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(GameOfLife CXX)
#Find the VTK-m package

@ -48,7 +48,7 @@
#include <vector>
static vtkm::Id3 dims(256, 256, 256);
static vtkm::Id3 dims(4, 4, 4);
static vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 3>> verticesArray, normalsArray;
static vtkm::cont::ArrayHandle<vtkm::Float32> scalarsArray;
static Quaternion qrot;
@ -245,7 +245,7 @@ int main(int argc, char* argv[])
vtkm::filter::MarchingCubes filter;
filter.SetGenerateNormals(true);
filter.SetMergeDuplicatePoints(false);
filter.SetIsoValue(0, 0.5);
filter.SetIsoValue(0, 0.1);
vtkm::filter::Result result = filter.Execute(dataSet, dataSet.GetField("nodevar"));
filter.MapFieldOntoOutput(result, dataSet.GetField("nodevar"));

@ -763,6 +763,28 @@ public:
DerivedAlgorithm::Sort(zipHandle, internal::KeyCompare<T, U, BinaryCompare>(binary_compare));
}
template <typename T, typename U, class StorageT, class StorageU, class BinaryFunctor>
VTKM_CONT static void Transform(vtkm::cont::ArrayHandle<T, StorageT>& input1,
vtkm::cont::ArrayHandle<T, StorageT>& input2,
vtkm::cont::ArrayHandle<U, StorageU>& output,
BinaryFunctor binaryFunctor)
{
vtkm::Id numValues = vtkm::Min(input1.GetNumberOfValues(), input2.GetNumberOfValues());
if (numValues <= 0)
{
return;
}
auto input1Portal = input1.PrepareForInput(DeviceAdapterTag());
auto input2Portal = input2.PrepareForInput(DeviceAdapterTag());
auto outputPortal = output.PrepareForOutput(numValues, DeviceAdapterTag());
BinaryTransformKernel<decltype(input1Portal), decltype(outputPortal), BinaryFunctor>
binaryKernel(input1Portal, input2Portal, outputPortal, binaryFunctor);
DerivedAlgorithm::Schedule(binaryKernel, numValues);
}
//};
//--------------------------------------------------------------------------
// Unique
template <typename T, class Storage>

@ -881,6 +881,37 @@ struct ScanKernel : vtkm::exec::FunctorBase
}
}
};
template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
struct BinaryTransformKernel : vtkm::exec::FunctorBase
{
using ValueType = typename InPortalType::ValueType;
InPortalType InPortal1;
InPortalType InPortal2;
OutPortalType OutPortal;
BinaryFunctor BinaryOperator;
VTKM_CONT
BinaryTransformKernel(const InPortalType& inPortal1,
const InPortalType& inPortal2,
const OutPortalType& outPortal,
BinaryFunctor binaryOperator)
: InPortal1(inPortal1)
, InPortal2(inPortal2)
, OutPortal(outPortal)
, BinaryOperator(binaryOperator)
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC
void operator()(vtkm::Id index) const
{
this->OutPortal.Set(
index, this->BinaryOperator(this->InPortal1.Get(index), this->InPortal2.Get(index)));
}
};
}
}
} // namespace vtkm::cont::internal

@ -0,0 +1,218 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_CellSetDualGraph_h
#define vtk_m_worklet_CellSetDualGraph_h
#include <vtkm/cont/CellSetSingleType.h>
struct EdgeCount : public vtkm::worklet::WorkletMapPointToCell
{
typedef void ControlSignature(CellSetIn, FieldOutCell<> numEdgesInCell);
typedef _2 ExecutionSignature(CellShape, PointCount);
using InputDomain = _1;
template <typename CellShapeTag>
VTKM_EXEC vtkm::IdComponent operator()(CellShapeTag cellShape, vtkm::IdComponent pointCount) const
{
return vtkm::exec::CellEdgeNumberOfEdges(pointCount, cellShape, *this);
}
};
struct EdgeExtract : public vtkm::worklet::WorkletMapPointToCell
{
typedef void ControlSignature(CellSetIn, FieldOutCell<> cellIndices, FieldOutCell<> edgeIndices);
typedef void ExecutionSignature(CellShape, InputIndex, PointIndices, VisitIndex, _2, _3);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT ScatterType GetScatter() const { return this->Scatter; }
VTKM_CONT EdgeExtract(const ScatterType& scatter)
: Scatter(scatter)
{
}
template <typename CellShapeTag,
typename CellIndexType,
typename PointIndexVecType,
typename EdgeIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
CellIndexType cellIndex,
PointIndexVecType& pointIndices,
vtkm::IdComponent visitIndex,
CellIndexType& cellIndexOut,
EdgeIndexVecType& edgeIndices) const
{
cellIndexOut = cellIndex;
edgeIndices = vtkm::exec::CellEdgeCanonicalId(
pointIndices.GetNumberOfComponents(), visitIndex, cellShape, pointIndices, *this);
};
private:
ScatterType Scatter;
};
struct CellToCellConnectivity : public vtkm::worklet::WorkletMapField
{
typedef void ControlSignature(FieldIn<> index,
WholeArrayIn<> cells,
WholeArrayOut<> from,
WholeArrayOut<> to);
typedef void ExecutionSignature(_1, InputIndex, _2, _3, _4);
using InputDomain = _1;
template <typename ConnectivityPortalType, typename CellIdPortalType>
VTKM_EXEC void operator()(vtkm::Id offset,
vtkm::Id index,
const CellIdPortalType& cells,
ConnectivityPortalType& from,
ConnectivityPortalType& to) const
{
from.Set(index * 2, cells.Get(offset));
to.Set(index * 2, cells.Get(offset + 1));
from.Set(index * 2 + 1, cells.Get(offset + 1));
to.Set(index * 2 + 1, cells.Get(offset));
}
};
template <typename DeviceAdapter>
class CellSetDualGraph
{
public:
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
struct degree2
{
VTKM_EXEC
bool operator()(vtkm::Id degree) const { return degree == 2; }
};
template <typename T>
void EdgeToCellConnectivity(const vtkm::cont::CellSetSingleType<T>& cellSet,
vtkm::cont::ArrayHandle<vtkm::Id>& cellIds,
vtkm::cont::ArrayHandle<vtkm::Id2>& cellEdges) const
{
// Get number of edges for each cell and use it as scatter count.
vtkm::cont::ArrayHandle<vtkm::IdComponent> numEdgesPerCell;
vtkm::worklet::DispatcherMapTopology<EdgeCount> edgesPerCellDisp;
edgesPerCellDisp.Invoke(cellSet, numEdgesPerCell);
// Get uncompress Cell to Edge mapping
vtkm::worklet::ScatterCounting scatter{ numEdgesPerCell, DeviceAdapter() };
vtkm::worklet::DispatcherMapTopology<EdgeExtract> edgeExtractDisp{ scatter };
edgeExtractDisp.Invoke(cellSet, cellIds, cellEdges);
}
template <typename T>
void Run(vtkm::cont::CellSetSingleType<T>& cellSet,
vtkm::cont::ArrayHandle<vtkm::Id>& numIndicesArray,
vtkm::cont::ArrayHandle<vtkm::Id>& indexOffsetArray,
vtkm::cont::ArrayHandle<vtkm::Id>& connectivityArray) const
{
// calculate the uncompressed Edge to Cell connectivity from Point to Cell connectivity
// in the CellSet
vtkm::cont::ArrayHandle<vtkm::Id> cellIds;
vtkm::cont::ArrayHandle<vtkm::Id2> cellEdges;
EdgeToCellConnectivity(cellSet, cellIds, cellEdges);
// for (int i = 0; i < cellIds.GetNumberOfValues(); i++) {
// std::cout << cellIds.GetPortalConstControl().Get(i) << " "
// << cellEdges.GetPortalConstControl().Get(i) << std::endl;
// }
// sort cell ids by cell edges, this groups cells by cell edges
Algorithm::SortByKey(cellEdges, cellIds);
// for (int i = 0; i < cellIds.GetNumberOfValues(); i++) {
// std::cout << cellEdges.GetPortalConstControl().Get(i) << " "
// << cellIds.GetPortalConstControl().Get(i) << std::endl;
// }
// count how many times an edge is shared by cells.
vtkm::cont::ArrayHandle<vtkm::Id2> uniqueEdges;
vtkm::cont::ArrayHandle<vtkm::Id> uniqueEdgeDegree;
Algorithm::ReduceByKey(
cellEdges,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, cellEdges.GetNumberOfValues()),
uniqueEdges,
uniqueEdgeDegree,
vtkm::Add());
// for (int i = 0; i < uniqueEdges.GetNumberOfValues(); i++) {
// std::cout << uniqueEdges.GetPortalConstControl().Get(i) << " "
// << uniqueEdgeDegree.GetPortalConstControl().Get(i) << std::endl;
// }
// Extract edges shared by two cells
vtkm::cont::ArrayHandle<vtkm::Id2> sharedEdges;
Algorithm::CopyIf(uniqueEdges, uniqueEdgeDegree, sharedEdges, degree2());
// for (int i = 0; i < sharedEdges.GetNumberOfValues(); i++) {
// std::cout << "graph edge: " << sharedEdges.GetPortalConstControl().Get(i)
// << std::endl;
// }
// find shared edges within all the edges.
vtkm::cont::ArrayHandle<vtkm::Id> lb;
Algorithm::LowerBounds(cellEdges, sharedEdges, lb);
// for (int i = 0; i < lb.GetNumberOfValues(); i++) {
// std::cout << "lower bound: " << lb.GetPortalConstControl().Get(i)
// << std::endl;
// }
// take each shared edge and the cells to create 2 edges of the dual graph
vtkm::cont::ArrayHandle<vtkm::Id> connFrom;
vtkm::cont::ArrayHandle<vtkm::Id> connTo;
connFrom.Allocate(sharedEdges.GetNumberOfValues() * 2);
connTo.Allocate(sharedEdges.GetNumberOfValues() * 2);
vtkm::worklet::DispatcherMapField<CellToCellConnectivity> c2cDisp;
c2cDisp.Invoke(lb, cellIds, connFrom, connTo);
// for (int i = 0; i < connFrom.GetNumberOfValues(); i++) {
// std::cout << "from cell: " << connFrom.GetPortalConstControl().Get(i)
// << ", to cell: " << connTo.GetPortalConstControl().Get(i)
// << std::endl;
// }
// Turn
Algorithm::SortByKey(connFrom, connTo);
// for (int i = 0; i < connFrom.GetNumberOfValues(); i++) {
// std::cout << "from cell: " << connFrom.GetPortalConstControl().Get(i)
// << ", to cell: " << connTo.GetPortalConstControl().Get(i)
// << std::endl;
// }
Algorithm::Copy(connTo, connectivityArray);
vtkm::cont::ArrayHandle<vtkm::Id> dualGraphVertices;
Algorithm::ReduceByKey(
connFrom,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, connFrom.GetNumberOfValues()),
dualGraphVertices,
numIndicesArray,
vtkm::Add());
// for (int i = 0; i < dualGraphVertices.GetNumberOfValues(); i++) {
// std::cout << "dual graph vertex: " << dualGraphVertices.GetPortalConstControl().Get(i)
// << ", degree: " << numIndicesArray.GetPortalConstControl().Get(i)
// << std::endl;
// }
Algorithm::ScanExclusive(numIndicesArray, indexOffsetArray);
}
};
#endif //vtk_m_worklet_CellSetDualGraph_h

@ -0,0 +1,145 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_connectivity_graph_connectivity_h
#define vtk_m_worklet_connectivity_graph_connectivity_h
#include <vtkm/worklet/connectivities/CellSetDualGraph.h>
#include <vtkm/worklet/connectivities/InnerJoin.h>
class Graft : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> index,
FieldIn<IdType> start,
FieldIn<IdType> degree,
WholeArrayIn<IdType> ids,
WholeArrayInOut<IdType> comp);
typedef void ExecutionSignature(_1, _2, _3, _4, _5);
typedef _1 InputDomain;
// TODO: Use Scatter?
template <typename InPortalType, typename InOutPortalType>
VTKM_EXEC void operator()(vtkm::Id index,
vtkm::Id start,
vtkm::Id degree,
const InPortalType& conn,
InOutPortalType& comp) const
{
for (vtkm::Id offset = start; offset < start + degree; offset++)
{
vtkm::Id neighbor = conn.Get(offset);
if ((comp.Get(index) == comp.Get(comp.Get(index))) && (comp.Get(neighbor) < comp.Get(index)))
{
comp.Set(comp.Get(index), comp.Get(neighbor));
}
}
}
};
class PointerJumping : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> index, WholeArrayInOut<IdType> comp);
typedef void ExecutionSignature(_1, _2);
typedef _1 InputDomain;
template <typename InOutPortalType>
VTKM_EXEC void operator()(vtkm::Id index, InOutPortalType& comp) const
{
while (comp.Get(comp.Get(index)) != comp.Get(index))
comp.Set(index, comp.Get(comp.Get(index)));
//vtkm::Id parent = comp.Get(index);
//comp.Set(index, comp.Get(comp.Get(index)));
};
};
class IsStar : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> index, WholeArrayIn<IdType> comp, FieldOut<bool>);
typedef _3 ExecutionSignature(_1, _2);
typedef _1 InputDomain;
template <typename InOutPortalType>
VTKM_EXEC bool operator()(vtkm::Id index, InOutPortalType& comp) const
{
return comp.Get(index) == comp.Get(comp.Get(index));
}
};
template <typename DeviceAdapter>
class GraphConnectivity
{
public:
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
template <typename InputPortalType, typename OutputPortalType>
void Run(const InputPortalType& numIndexArray,
const InputPortalType& indexOffsetArray,
const InputPortalType& connectivityArray,
OutputPortalType& componentsOut) const
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
bool allStar = false;
vtkm::cont::ArrayHandle<vtkm::Id> components;
vtkm::cont::ArrayHandle<bool> isStar;
vtkm::cont::ArrayHandle<vtkm::Id> cellIds;
Algorithm::Copy(
vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, numIndexArray.GetNumberOfValues()), cellIds);
Algorithm::Copy(cellIds, components);
do
{
vtkm::worklet::DispatcherMapField<Graft> graftDispatcher;
graftDispatcher.Invoke(
cellIds, indexOffsetArray, numIndexArray, connectivityArray, components);
// Detection of allStar has be come before pointer jumping. Don't try to rearrange it.
vtkm::worklet::DispatcherMapField<IsStar> isStarDisp;
isStarDisp.Invoke(cellIds, components, isStar);
allStar = Algorithm::Reduce(isStar, true, vtkm::LogicalAnd());
vtkm::worklet::DispatcherMapField<PointerJumping> pointJumpingDispatcher;
pointJumpingDispatcher.Invoke(cellIds, components);
} while (!allStar);
// renumber connected component to the range of [0, number of components).
vtkm::cont::ArrayHandle<vtkm::Id> uniqueComponents;
Algorithm::Copy(components, uniqueComponents);
Algorithm::Sort(uniqueComponents);
Algorithm::Unique(uniqueComponents);
vtkm::cont::ArrayHandle<vtkm::Id> uniqueColor;
Algorithm::Copy(
vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, uniqueComponents.GetNumberOfValues()),
uniqueColor);
vtkm::cont::ArrayHandle<vtkm::Id> cellColors;
vtkm::cont::ArrayHandle<vtkm::Id> cellIdsOut;
InnerJoin<DeviceAdapter>().Run(
components, cellIds, uniqueComponents, uniqueColor, cellColors, cellIdsOut, componentsOut);
Algorithm::SortByKey(cellIdsOut, componentsOut);
}
};
#endif //vtk_m_worklet_connectivity_graph_connectivity_h

@ -0,0 +1,105 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_InnerJoin_h
#define vtk_m_worklet_InnerJoin_h
template <typename DeviceAdapter>
class InnerJoin
{
public:
struct Merge : vtkm::worklet::WorkletMapField
{
typedef void ControlSignature(FieldIn<vtkm::Id>,
FieldIn<vtkm::Id>,
FieldIn<vtkm::Id>,
WholeArrayIn<vtkm::Id>,
FieldOut<>,
FieldOut<>,
FieldOut<>);
typedef void ExecutionSignature(_1, _2, _3, VisitIndex, _4, _5, _6, _7);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT
ScatterType GetScatter() const { return this->Scatter; }
VTKM_CONT
Merge(const ScatterType& scatter)
: Scatter(scatter)
{
}
template <typename InPortalType>
VTKM_EXEC void operator()(vtkm::Id key,
vtkm::Id value1,
vtkm::Id lowerBounds,
vtkm::Id visitIndex,
const InPortalType& value2,
vtkm::Id& keyOut,
vtkm::Id& value1Out,
vtkm::Id& value2Out) const
{
auto v2 = value2.Get(lowerBounds + visitIndex);
keyOut = key;
value1Out = value1;
value2Out = v2;
}
private:
ScatterType Scatter;
};
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
// TODO: not mutating input keys and values?
template <typename Key, typename Value1, typename Value2>
void Run(vtkm::cont::ArrayHandle<Key>& key1,
vtkm::cont::ArrayHandle<Value1>& value1,
vtkm::cont::ArrayHandle<Key>& key2,
vtkm::cont::ArrayHandle<Value2>& value2,
vtkm::cont::ArrayHandle<Key>& keyOut,
vtkm::cont::ArrayHandle<Value1>& value1Out,
vtkm::cont::ArrayHandle<Value2>& value2Out) const
{
Algorithm::SortByKey(key1, value1);
Algorithm::SortByKey(key2, value2);
vtkm::cont::ArrayHandle<vtkm::Id> lbs;
vtkm::cont::ArrayHandle<vtkm::Id> ubs;
Algorithm::LowerBounds(key2, key1, lbs);
Algorithm::UpperBounds(key2, key1, ubs);
vtkm::cont::ArrayHandle<vtkm::Id> counts;
Algorithm::Transform(ubs, lbs, counts, vtkm::Subtract());
vtkm::cont::ArrayHandle<vtkm::Id> output_offset;
Algorithm::ScanExclusive(counts, output_offset);
vtkm::worklet::ScatterCounting scatter{ counts, DeviceAdapter() };
Merge merge(scatter);
vtkm::worklet::DispatcherMapField<Merge, DeviceAdapter> mergeDisp(merge);
mergeDisp.Invoke(key1, value1, lbs, value2, keyOut, value1Out, value2Out);
};
};
#endif //vtk_m_worklet_InnerJoin_h

@ -19,52 +19,55 @@
##============================================================================
set(unit_tests
UnitTestAverageByKey.cxx
UnitTestCellAverage.cxx
UnitTestCellDeepCopy.cxx
UnitTestCellGradient.cxx
UnitTestClipping.cxx
UnitTestContourTreeUniform.cxx
UnitTestCosmoTools.cxx
UnitTestExternalFaces.cxx
UnitTestExtractGeometry.cxx
UnitTestExtractPoints.cxx
UnitTestExtractStructured.cxx
UnitTestFieldHistogram.cxx
UnitTestFieldStatistics.cxx
UnitTestKdTreeBuildNNS.cxx
UnitTestKeys.cxx
UnitTestMagnitude.cxx
UnitTestMarchingCubes.cxx
UnitTestMask.cxx
UnitTestMaskPoints.cxx
UnitTestNDimsEntropy.cxx
UnitTestNDimsHistogram.cxx
UnitTestNDimsHistMarginalization.cxx
UnitTestParticleAdvection.cxx
UnitTestPointElevation.cxx
UnitTestPointGradient.cxx
UnitTestRemoveUnusedPoints.cxx
UnitTestScatterCounting.cxx
UnitTestScatterPermutation.cxx
UnitTestSplatKernels.cxx
UnitTestStreamingSine.cxx
UnitTestStreamLineUniformGrid.cxx
UnitTestSurfaceNormals.cxx
UnitTestTetrahedralize.cxx
UnitTestThreshold.cxx
UnitTestThresholdPoints.cxx
UnitTestTriangulate.cxx
UnitTestWholeCellSetIn.cxx
UnitTestWorkletMapField.cxx
UnitTestWorkletMapFieldExecArg.cxx
UnitTestWorkletMapFieldWholeArray.cxx
UnitTestWorkletMapPointNeighborhood.cxx
UnitTestWorkletMapTopologyExplicit.cxx
UnitTestWorkletMapTopologyUniform.cxx
UnitTestWorkletReduceByKey.cxx
UnitTestVertexClustering.cxx
UnitTestWaveletCompressor.cxx
# UnitTestAverageByKey.cxx
# UnitTestCellAverage.cxx
# UnitTestCellDeepCopy.cxx
# UnitTestCellGradient.cxx
# UnitTestClipping.cxx
# UnitTestContourTreeUniform.cxx
# UnitTestCosmoTools.cxx
UnitTestDualGraph.cxx
# UnitTestExternalFaces.cxx
# UnitTestExtractGeometry.cxx
# UnitTestExtractPoints.cxx
# UnitTestExtractStructured.cxx
# UnitTestFieldHistogram.cxx
# UnitTestFieldStatistics.cxx
UnitTestGraphConnectivity.cpp
UnitTestInnerJoin.cxx
# UnitTestKdTreeBuildNNS.cxx
# UnitTestKeys.cxx
# UnitTestMagnitude.cxx
# UnitTestMarchingCubes.cxx
# UnitTestMask.cxx
# UnitTestMaskPoints.cxx
# UnitTestNDimsEntropy.cxx
# UnitTestNDimsHistogram.cxx
# UnitTestNDimsHistMarginalization.cxx
# UnitTestParticleAdvection.cxx
# UnitTestPointElevation.cxx
# UnitTestPointGradient.cxx
# UnitTestRemoveUnusedPoints.cxx
# UnitTestScatterCounting.cxx
# UnitTestScatterPermutation.cxx
# UnitTestSplatKernels.cxx
# UnitTestStreamingSine.cxx
# UnitTestStreamLineUniformGrid.cxx
# UnitTestSurfaceNormals.cxx
# UnitTestTetrahedralize.cxx
# UnitTestThreshold.cxx
# UnitTestThresholdPoints.cxx
# UnitTestTriangulate.cxx
# UnitTestWholeCellSetIn.cxx
# UnitTestWorkletMapField.cxx
# UnitTestWorkletMapFieldExecArg.cxx
# UnitTestWorkletMapFieldWholeArray.cxx
# UnitTestWorkletMapPointNeighborhood.cxx
# UnitTestWorkletMapTopologyExplicit.cxx
# UnitTestWorkletMapTopologyUniform.cxx
# UnitTestWorkletReduceByKey.cxx
# UnitTestVertexClustering.cxx
# UnitTestWaveletCompressor.cxx
)
vtkm_save_worklet_unit_tests(${unit_tests})

@ -0,0 +1,217 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/DispatcherReduceByKey.h>
#include <vtkm/worklet/Keys.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/worklet/WorkletReduceByKey.h>
#include <vtkm/filter/MarchingCubes.h>
#include <vtkm/worklet/connectivities/CellSetDualGraph.h>
class TangleField : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexId, FieldOut<Scalar> v);
typedef void ExecutionSignature(_1, _2);
typedef _1 InputDomain;
const vtkm::Id xdim, ydim, zdim;
const vtkm::FloatDefault xmin, ymin, zmin, xmax, ymax, zmax;
const vtkm::Id cellsPerLayer;
VTKM_CONT
TangleField(const vtkm::Id3 dims,
const vtkm::FloatDefault mins[3],
const vtkm::FloatDefault maxs[3])
: xdim(dims[0])
, ydim(dims[1])
, zdim(dims[2])
, xmin(mins[0])
, ymin(mins[1])
, zmin(mins[2])
, xmax(maxs[0])
, ymax(maxs[1])
, zmax(maxs[2])
, cellsPerLayer((xdim) * (ydim))
{
}
VTKM_EXEC
void operator()(const vtkm::Id& vertexId, vtkm::Float32& v) const
{
const vtkm::Id x = vertexId % (xdim);
const vtkm::Id y = (vertexId / (xdim)) % (ydim);
const vtkm::Id z = vertexId / cellsPerLayer;
const vtkm::FloatDefault fx =
static_cast<vtkm::FloatDefault>(x) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::FloatDefault fy =
static_cast<vtkm::FloatDefault>(y) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::FloatDefault fz =
static_cast<vtkm::FloatDefault>(z) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::Float32 xx = 3.0f * vtkm::Float32(xmin + (xmax - xmin) * (fx));
const vtkm::Float32 yy = 3.0f * vtkm::Float32(ymin + (ymax - ymin) * (fy));
const vtkm::Float32 zz = 3.0f * vtkm::Float32(zmin + (zmax - zmin) * (fz));
v = (xx * xx * xx * xx - 5.0f * xx * xx + yy * yy * yy * yy - 5.0f * yy * yy +
zz * zz * zz * zz - 5.0f * zz * zz + 11.8f) *
0.2f +
0.5f;
}
};
vtkm::cont::DataSet MakeIsosurfaceTestDataSet(vtkm::Id3 dims)
{
vtkm::cont::DataSet dataSet;
const vtkm::Id3 vdims(dims[0] + 1, dims[1] + 1, dims[2] + 1);
vtkm::FloatDefault mins[3] = { -1.0f, -1.0f, -1.0f };
vtkm::FloatDefault maxs[3] = { 1.0f, 1.0f, 1.0f };
vtkm::cont::ArrayHandle<vtkm::Float32> pointFieldArray;
vtkm::cont::ArrayHandleIndex vertexCountImplicitArray(vdims[0] * vdims[1] * vdims[2]);
vtkm::worklet::DispatcherMapField<TangleField> tangleFieldDispatcher(
TangleField(vdims, mins, maxs));
tangleFieldDispatcher.Invoke(vertexCountImplicitArray, pointFieldArray);
vtkm::Id numCells = dims[0] * dims[1] * dims[2];
auto cellFieldArray = vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(0, 1, numCells);
vtkm::Vec<vtkm::FloatDefault, 3> origin(0.0f, 0.0f, 0.0f);
vtkm::Vec<vtkm::FloatDefault, 3> spacing(1.0f / static_cast<vtkm::FloatDefault>(dims[0]),
1.0f / static_cast<vtkm::FloatDefault>(dims[2]),
1.0f / static_cast<vtkm::FloatDefault>(dims[1]));
vtkm::cont::ArrayHandleUniformPointCoordinates coordinates(vdims, origin, spacing);
dataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", coordinates));
static const vtkm::IdComponent ndim = 3;
vtkm::cont::CellSetStructured<ndim> cellSet("cells");
cellSet.SetPointDimensions(vdims);
dataSet.AddCellSet(cellSet);
dataSet.AddField(vtkm::cont::Field("nodevar", vtkm::cont::Field::ASSOC_POINTS, pointFieldArray));
dataSet.AddField(
vtkm::cont::Field("cellvar", vtkm::cont::Field::ASSOC_CELL_SET, "cells", cellFieldArray));
return dataSet;
}
template <typename DeviceAdapter>
class TestDualGraph
{
public:
void TestTriangleMesh() const
{
// cell2vertices connectivityusing Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
//std::vector<vtkm::Id> connectivity = {0, 2, 1, 1, 2, 4, 1, 4, 3, 2, 5, 4};
std::vector<vtkm::Id> connectivity = { 0, 2, 4, 1, 3, 5, 2, 6, 4, 5, 3, 7, 2, 9, 6, 4, 6, 8 };
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(8, vtkm::CELL_SHAPE_TRIANGLE, 3, vtkm::cont::make_ArrayHandle(connectivity));
vtkm::cont::ArrayHandle<vtkm::Id> numIndicesArray;
vtkm::cont::ArrayHandle<vtkm::Id> indexOffsetArray;
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
CellSetDualGraph<DeviceAdapter>().Run(
cellSet, numIndicesArray, indexOffsetArray, connectivityArray);
std::cout << "numIndices: ";
for (int i = 0; i < numIndicesArray.GetNumberOfValues(); i++)
{
std::cout << numIndicesArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
std::cout << "indexOffset: ";
for (int i = 0; i < indexOffsetArray.GetNumberOfValues(); i++)
{
std::cout << indexOffsetArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
std::cout << "connectivity: ";
for (int i = 0; i < connectivityArray.GetNumberOfValues(); i++)
{
std::cout << connectivityArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
}
void TestIsosurface() const
{
vtkm::Id3 dims(3, 3, 3);
vtkm::cont::DataSet dataSet = MakeIsosurfaceTestDataSet(dims);
vtkm::filter::MarchingCubes filter;
filter.SetGenerateNormals(true);
filter.SetMergeDuplicatePoints(true);
filter.SetIsoValue(0, 0.5);
vtkm::filter::Result result = filter.Execute(dataSet, dataSet.GetField("nodevar"));
vtkm::cont::DataSet& outputData = result.GetDataSet();
auto cellSet = outputData.GetCellSet().Cast<vtkm::cont::CellSetSingleType<>>();
vtkm::cont::ArrayHandle<vtkm::Id> numIndicesArray;
vtkm::cont::ArrayHandle<vtkm::Id> indexOffsetArray;
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
CellSetDualGraph<DeviceAdapter>().Run(
cellSet, numIndicesArray, indexOffsetArray, connectivityArray);
std::cout << "numIndices: ";
for (int i = 0; i < numIndicesArray.GetNumberOfValues(); i++)
{
std::cout << numIndicesArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
std::cout << "indexOffset: ";
for (int i = 0; i < indexOffsetArray.GetNumberOfValues(); i++)
{
std::cout << indexOffsetArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
std::cout << "connectivity: ";
for (int i = 0; i < connectivityArray.GetNumberOfValues(); i++)
{
std::cout << connectivityArray.GetPortalConstControl().Get(i) << " ";
}
std::cout << std::endl;
}
void operator()() const
{
//this->TestTriangleMesh();
this->TestIsosurface();
}
};
int UnitTestDualGraph(int, char* [])
{
return vtkm::cont::testing::Testing::Run(TestDualGraph<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>());
}

@ -0,0 +1,209 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/exec/CellEdge.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/Keys.h>
#include <vtkm/worklet/WorkletReduceByKey.h>
#include <vtkm/worklet/DispatcherReduceByKey.h>
#include <vtkm/worklet/connectivities/CellSetDualGraph.h>
#include <vtkm/worklet/connectivities/GraphConnectivity.h>
#include <vtkm/filter/MarchingCubes.h>
class TangleField : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<IdType> vertexId, FieldOut<Scalar> v);
typedef void ExecutionSignature(_1, _2);
typedef _1 InputDomain;
const vtkm::Id xdim, ydim, zdim;
const vtkm::FloatDefault xmin, ymin, zmin, xmax, ymax, zmax;
const vtkm::Id cellsPerLayer;
VTKM_CONT
TangleField(const vtkm::Id3 dims,
const vtkm::FloatDefault mins[3],
const vtkm::FloatDefault maxs[3])
: xdim(dims[0])
, ydim(dims[1])
, zdim(dims[2])
, xmin(mins[0])
, ymin(mins[1])
, zmin(mins[2])
, xmax(maxs[0])
, ymax(maxs[1])
, zmax(maxs[2])
, cellsPerLayer((xdim) * (ydim))
{
}
VTKM_EXEC
void operator()(const vtkm::Id& vertexId, vtkm::Float32& v) const
{
const vtkm::Id x = vertexId % (xdim);
const vtkm::Id y = (vertexId / (xdim)) % (ydim);
const vtkm::Id z = vertexId / cellsPerLayer;
const vtkm::FloatDefault fx =
static_cast<vtkm::FloatDefault>(x) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::FloatDefault fy =
static_cast<vtkm::FloatDefault>(y) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::FloatDefault fz =
static_cast<vtkm::FloatDefault>(z) / static_cast<vtkm::FloatDefault>(xdim - 1);
const vtkm::Float32 xx = 3.0f * vtkm::Float32(xmin + (xmax - xmin) * (fx));
const vtkm::Float32 yy = 3.0f * vtkm::Float32(ymin + (ymax - ymin) * (fy));
const vtkm::Float32 zz = 3.0f * vtkm::Float32(zmin + (zmax - zmin) * (fz));
v = (xx * xx * xx * xx - 5.0f * xx * xx + yy * yy * yy * yy - 5.0f * yy * yy +
zz * zz * zz * zz - 5.0f * zz * zz + 11.8f) *
0.2f +
0.5f;
}
};
static vtkm::cont::DataSet MakeIsosurfaceTestDataSet(vtkm::Id3 dims)
{
vtkm::cont::DataSet dataSet;
const vtkm::Id3 vdims(dims[0] + 1, dims[1] + 1, dims[2] + 1);
vtkm::FloatDefault mins[3] = { -1.0f, -1.0f, -1.0f };
vtkm::FloatDefault maxs[3] = { 1.0f, 1.0f, 1.0f };
vtkm::cont::ArrayHandle<vtkm::Float32> pointFieldArray;
vtkm::cont::ArrayHandleIndex vertexCountImplicitArray(vdims[0] * vdims[1] * vdims[2]);
vtkm::worklet::DispatcherMapField<TangleField> tangleFieldDispatcher(
TangleField(vdims, mins, maxs));
tangleFieldDispatcher.Invoke(vertexCountImplicitArray, pointFieldArray);
vtkm::Id numCells = dims[0] * dims[1] * dims[2];
auto cellFieldArray = vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(0, 1, numCells);
vtkm::Vec<vtkm::FloatDefault, 3> origin(0.0f, 0.0f, 0.0f);
vtkm::Vec<vtkm::FloatDefault, 3> spacing(1.0f / static_cast<vtkm::FloatDefault>(dims[0]),
1.0f / static_cast<vtkm::FloatDefault>(dims[2]),
1.0f / static_cast<vtkm::FloatDefault>(dims[1]));
vtkm::cont::ArrayHandleUniformPointCoordinates coordinates(vdims, origin, spacing);
dataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", coordinates));
static const vtkm::IdComponent ndim = 3;
vtkm::cont::CellSetStructured<ndim> cellSet("cells");
cellSet.SetPointDimensions(vdims);
dataSet.AddCellSet(cellSet);
dataSet.AddField(vtkm::cont::Field("nodevar", vtkm::cont::Field::ASSOC_POINTS, pointFieldArray));
dataSet.AddField(
vtkm::cont::Field("cellvar", vtkm::cont::Field::ASSOC_CELL_SET, "cells", cellFieldArray));
return dataSet;
}
template <typename DeviceAdapter>
class TestGraphConnectivity
{
public:
void TestGrafting() const
{
// std::vector<vtkm::Id> ids = {0, 1, 2, 3};
// std::vector<vtkm::Id> conn = {1, 0, 2, 3, 1, 1};
// std::vector<vtkm::Id> starts = {0, 1, 4, 5};
// std::vector<vtkm::Id> ends = {1, 4, 5, 6};
// std::vector<vtkm::Id> degrees = {1, 3, 1, 1};
// std::vector<vtkm::Id> comp = {0, 1, 2, 3};
// std::vector<vtkm::Id> ids = {0, 1, 2, 3, 4};
// std::vector<vtkm::Id> conn = {1, 2, 0, 2, 0, 1, 4, 3};
// std::vector<vtkm::Id> starts = {0, 2, 4, 6, 7};
// std::vector<vtkm::Id> ends = {2, 4, 6, 7, 8};
// std::vector<vtkm::Id> degrees = {2, 2, 2, 1, 1};
// std::vector<vtkm::Id> comp = {0, 1, 2, 3, 4};
// vtkm::cont::ArrayHandle<vtkm::Id> idsArr = vtkm::cont::make_ArrayHandle(ids);
// vtkm::cont::ArrayHandle<vtkm::Id> connArr = vtkm::cont::make_ArrayHandle(conn);
// vtkm::cont::ArrayHandle<vtkm::Id> startsArr = vtkm::cont::make_ArrayHandle(starts);
// vtkm::cont::ArrayHandle<vtkm::Id> endsArr = vtkm::cont::make_ArrayHandle(ends);
// vtkm::cont::ArrayHandle<vtkm::Id> degreesArr = vtkm::cont::make_ArrayHandle(degrees);
// vtkm::cont::ArrayHandle<vtkm::Id> compArr = vtkm::cont::make_ArrayHandle(comp);
// for (int i = 0; i < compArr.GetNumberOfValues(); i++) {
// std::cout << compArr.GetPortalConstControl().Get(i) << " ";
// }
// std::cout << std::endl;
// std::vector<vtkm::Id> connectivity = { 0, 2, 4, 1, 3, 5, 2, 6, 4, 5, 3, 7, 2, 9, 6, 4, 6, 8};
// vtkm::cont::CellSetSingleType<> cellSet;
// cellSet.Fill(8,
// vtkm::CELL_SHAPE_TRIANGLE,
// 3,
// vtkm::cont::make_ArrayHandle(connectivity));
vtkm::Id3 dims(4, 4, 4);
vtkm::cont::DataSet dataSet = MakeIsosurfaceTestDataSet(dims);
vtkm::filter::MarchingCubes filter;
filter.SetGenerateNormals(true);
filter.SetMergeDuplicatePoints(true);
filter.SetIsoValue(0, 0.1);
vtkm::filter::Result result = filter.Execute(dataSet, dataSet.GetField("nodevar"));
vtkm::cont::DataSet& outputData = result.GetDataSet();
auto cellSet = outputData.GetCellSet().Cast<vtkm::cont::CellSetSingleType<>>();
vtkm::cont::ArrayHandle<vtkm::Id> numIndicesArray;
vtkm::cont::ArrayHandle<vtkm::Id> indexOffsetArray;
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
CellSetDualGraph<DeviceAdapter>().Run(cellSet,
numIndicesArray,
indexOffsetArray,
connectivityArray);
vtkm::cont::ArrayHandle<vtkm::Id> componentArray;
GraphConnectivity<DeviceAdapter>().Run(numIndicesArray,
indexOffsetArray,
connectivityArray,
componentArray);
for (int i = 0; i < componentArray.GetNumberOfValues(); i++)
{
std::cout << i << " "
<< componentArray.GetPortalConstControl().Get(i) << std::endl;
}
std::cout << std::endl;
}
void operator()() const
{
this->TestGrafting();
}
};
int UnitTestGraphConnectivity(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestGraphConnectivity<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>());
}

@ -0,0 +1,53 @@
//
// Created by ollie on 12/19/17.
//
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/worklet/connectivities/InnerJoin.h>
template <typename DeviceAdapter>
class TestInnerJoin
{
public:
void TestTwoArrays() const
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>;
std::vector<vtkm::Id> A = { 8, 3, 6, 8, 9, 5, 12, 10, 14 };
std::vector<vtkm::Id> B = { 7, 11, 9, 8, 5, 1, 0, 5 };
vtkm::cont::ArrayHandle<vtkm::Id> A_arr = vtkm::cont::make_ArrayHandle(A);
vtkm::cont::ArrayHandle<vtkm::Id> B_arr = vtkm::cont::make_ArrayHandle(B);
vtkm::cont::ArrayHandle<vtkm::Id> idxA;
vtkm::cont::ArrayHandle<vtkm::Id> idxB;
Algorithm::Copy(vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, A_arr.GetNumberOfValues()),
idxA);
Algorithm::Copy(vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, B_arr.GetNumberOfValues()),
idxB);
vtkm::cont::ArrayHandle<vtkm::Id> joinedIndex;
vtkm::cont::ArrayHandle<vtkm::Id> outA;
vtkm::cont::ArrayHandle<vtkm::Id> outB;
InnerJoin<DeviceAdapter>().Run(A_arr, idxA, B_arr, idxB, joinedIndex, outA, outB);
for (int i = 0; i < joinedIndex.GetNumberOfValues(); i++)
{
std::cout << "key: " << joinedIndex.GetPortalConstControl().Get(i)
<< ", value1: " << outA.GetPortalConstControl().Get(i)
<< ", value2: " << outB.GetPortalConstControl().Get(i) << std::endl;
}
}
void operator()() const { this->TestTwoArrays(); }
};
int UnitTestInnerJoin(int, char* [])
{
return vtkm::cont::testing::Testing::Run(TestInnerJoin<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>());
}