Merge topic 'external-face-more-generic'

dcbbb727 Merge branch 'master' into external-face-more-generic
0703139a Make Keys class do in-place sort
059c7f6d Fix issue with ExternalFaces on CellSetSingleType
876514ba Add better test for external faces
53679dfc Update ExternalFaces to support mixed face types

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Brent Lessley <blessley@cs.uoregon.edu>
Merge-request: !662
This commit is contained in:
Kenneth Moreland 2017-02-16 15:28:51 +00:00 committed by Kitware Robot
commit d339025a1b
12 changed files with 730 additions and 373 deletions

@ -778,7 +778,7 @@ MakeTestDataSet::Make3DExplicitDataSet5()
CoordType(1, 1, 0), //5
CoordType(1, 1, 1), //6
CoordType(0, 1, 1), //7
CoordType(2, 0, 0), //8
CoordType(2, 0.5, 0.5), //8
CoordType(0, 2, 0), //9
CoordType(1, 2, 0) //10
};
@ -808,34 +808,34 @@ MakeTestDataSet::Make3DExplicitDataSet5()
cellSet.PrepareToAddCells(nCells, 23);
ids[0] = 0;
ids[1] = 4;
ids[1] = 1;
ids[2] = 5;
ids[3] = 1;
ids[3] = 4;
ids[4] = 3;
ids[5] = 7;
ids[5] = 2;
ids[6] = 6;
ids[7] = 2;
ids[7] = 7;
cellSet.AddCell(vtkm::CELL_SHAPE_HEXAHEDRON, 8, ids);
ids[0] = 1;
ids[1] = 2;
ids[1] = 5;
ids[2] = 6;
ids[3] = 5;
ids[3] = 2;
ids[4] = 8;
cellSet.AddCell(vtkm::CELL_SHAPE_PYRAMID, 5, ids);
ids[0] = 5;
ids[1] = 10;
ids[2] = 8;
ids[1] = 8;
ids[2] = 10;
ids[3] = 6;
cellSet.AddCell(vtkm::CELL_SHAPE_TETRA, 4, ids);
ids[0] = 4;
ids[1] = 9;
ids[2] = 7;
ids[1] = 7;
ids[2] = 9;
ids[3] = 5;
ids[4] = 10;
ids[5] = 6;
ids[4] = 6;
ids[5] = 10;
cellSet.AddCell(vtkm::CELL_SHAPE_WEDGE, 6, ids);
cellSet.CompleteAddingCells(nVerts);

@ -212,6 +212,23 @@ CellFaceNumberOfPoints(vtkm::IdComponent faceIndex,
return detail::NumPointsInFace[shape.Id][faceIndex];
}
template<typename CellShapeTag>
static inline VTKM_EXEC
vtkm::UInt8
CellFaceShape(vtkm::IdComponent faceIndex,
CellShapeTag shape,
const vtkm::exec::FunctorBase &worklet)
{
VTKM_ASSUME(faceIndex >= 0);
VTKM_ASSUME(faceIndex < detail::MAX_NUM_FACES);
switch (CellFaceNumberOfPoints(faceIndex, shape, worklet))
{
case 3: return vtkm::CELL_SHAPE_TRIANGLE;
case 4: return vtkm::CELL_SHAPE_QUAD;
default: return vtkm::CELL_SHAPE_POLYGON;
}
}
template<typename CellShapeTag>
static inline VTKM_EXEC
vtkm::VecCConst<vtkm::IdComponent>

@ -34,6 +34,8 @@ set(headers
FetchTagWholeCellSetIn.h
FromCount.h
FromIndices.h
InputIndex.h
OutputIndex.h
ThreadIndices.h
ThreadIndicesBasic.h
ThreadIndicesReduceByKey.h

@ -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 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.
//============================================================================
#ifndef vtk_m_exec_arg_InputIndex_h
#define vtk_m_exec_arg_InputIndex_h
#include <vtkm/exec/arg/Fetch.h>
#include <vtkm/exec/arg/ExecutionSignatureTagBase.h>
namespace vtkm {
namespace exec {
namespace arg {
/// \brief Aspect tag to use for getting the work index.
///
/// The \c AspectTagInputIndex aspect tag causes the \c Fetch class to ignore
/// whatever data is in the associated execution object and return the index
/// of the input element.
///
struct AspectTagInputIndex { };
/// \brief The \c ExecutionSignature tag to use to get the input index
///
/// When a worklet is dispatched, it broken into pieces defined by the input
/// domain and scheduled on independent threads. This tag in the \c
/// ExecutionSignature passes the index of the input element that the work
/// thread is currently working on. When a worklet has a scatter associated
/// with it, the input and output indices can be different. \c WorkletBase
/// contains a typedef that points to this class.
///
struct InputIndex : vtkm::exec::arg::ExecutionSignatureTagBase
{
// The index does not really matter because the fetch is going to ignore it.
// However, it still has to point to a valid parameter in the
// ControlSignature because the templating is going to grab a fetch tag
// whether we use it or not. 1 should be guaranteed to be valid since you
// need at least one argument for the input domain.
static const vtkm::IdComponent INDEX = 1;
typedef vtkm::exec::arg::AspectTagInputIndex AspectTag;
};
template<typename FetchTag, typename ThreadIndicesType, typename ExecObjectType>
struct Fetch<FetchTag,
vtkm::exec::arg::AspectTagInputIndex,
ThreadIndicesType,
ExecObjectType>
{
typedef vtkm::Id ValueType;
VTKM_EXEC
vtkm::Id Load(const ThreadIndicesType &indices, const ExecObjectType &) const
{
return indices.GetInputIndex();
}
VTKM_EXEC
void Store(const ThreadIndicesType &,
const ExecObjectType &,
const ValueType &) const
{
// Store is a no-op.
}
};
}
}
} // namespace vtkm::exec::arg
#endif //vtk_m_exec_arg_InputIndex_h

@ -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 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.
//============================================================================
#ifndef vtk_m_exec_arg_OutputIndex_h
#define vtk_m_exec_arg_OutputIndex_h
#include <vtkm/exec/arg/Fetch.h>
#include <vtkm/exec/arg/ExecutionSignatureTagBase.h>
namespace vtkm {
namespace exec {
namespace arg {
/// \brief Aspect tag to use for getting the work index.
///
/// The \c AspectTagOutputIndex aspect tag causes the \c Fetch class to ignore
/// whatever data is in the associated execution object and return the index
/// of the output element.
///
struct AspectTagOutputIndex { };
/// \brief The \c ExecutionSignature tag to use to get the output index
///
/// When a worklet is dispatched, it broken into pieces defined by the output
/// domain and scheduled on independent threads. This tag in the \c
/// ExecutionSignature passes the index of the output element that the work
/// thread is currently working on. When a worklet has a scatter associated
/// with it, the output and output indices can be different. \c WorkletBase
/// contains a typedef that points to this class.
///
struct OutputIndex : vtkm::exec::arg::ExecutionSignatureTagBase
{
// The index does not really matter because the fetch is going to ignore it.
// However, it still has to point to a valid parameter in the
// ControlSignature because the templating is going to grab a fetch tag
// whether we use it or not. 1 should be guaranteed to be valid since you
// need at least one argument for the output domain.
static const vtkm::IdComponent INDEX = 1;
typedef vtkm::exec::arg::AspectTagOutputIndex AspectTag;
};
template<typename FetchTag, typename ThreadIndicesType, typename ExecObjectType>
struct Fetch<FetchTag,
vtkm::exec::arg::AspectTagOutputIndex,
ThreadIndicesType,
ExecObjectType>
{
typedef vtkm::Id ValueType;
VTKM_EXEC
vtkm::Id Load(const ThreadIndicesType &indices, const ExecObjectType &) const
{
return indices.GetOutputIndex();
}
VTKM_EXEC
void Store(const ThreadIndicesType &,
const ExecObjectType &,
const ValueType &) const
{
// Store is a no-op.
}
};
}
}
} // namespace vtkm::exec::arg
#endif //vtk_m_exec_arg_OutputIndex_h

@ -40,41 +40,15 @@ public:
template<typename T, typename U, typename V, typename W>
void operator()(const vtkm::cont::CellSetExplicit<T,U,V,W>& cellset ) const
{
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::cont::ArrayHandle<vtkm::Id> conn;
vtkm::cont::ArrayHandle<vtkm::UInt8> output_shapes;
vtkm::cont::ArrayHandle<vtkm::IdComponent> output_numIndices;
vtkm::cont::ArrayHandle<vtkm::Id> output_conn;
shapes = cellset.GetShapesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
numIndices = cellset.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
conn = cellset.GetConnectivityArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::worklet::ExternalFaces exfaces;
exfaces.run(shapes, numIndices, conn,
output_shapes, output_numIndices, output_conn,
DeviceAdapter());
vtkm::cont::CellSetExplicit<> output_cs(cellset.GetName());
output_cs.Fill(cellset.GetNumberOfPoints(),
output_shapes,
output_numIndices,
output_conn);
vtkm::worklet::ExternalFaces exfaces;
exfaces.Run(cellset, output_cs, DeviceAdapter());
this->Output->AddCellSet(output_cs);
*this->Valid = true;
}
template<typename T>
void operator()(const T& ) const
void operator()(const vtkm::cont::CellSet& ) const
{
//don't support this cell type
*this->Valid = false;

@ -27,9 +27,9 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
@ -37,9 +37,11 @@
#include <vtkm/cont/Timer.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/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletReduceByKey.h>
// #define __VTKM_EXTERNAL_FACES_BENCHMARK
@ -61,36 +63,6 @@ struct ExternalFaces
}
};
//Functor that returns an index into the cell-point connectivity array,
//given an index for the face-point connectivity array.
struct GetConnIndex
{
private:
vtkm::Id FacesPerCell;
vtkm::Id PointsPerCell;
public:
VTKM_CONT
GetConnIndex() {};
VTKM_CONT
GetConnIndex(const vtkm::Id &f,
const vtkm::Id &p) :
FacesPerCell(f),
PointsPerCell(p)
{};
VTKM_EXEC_CONT
vtkm::Id operator()(vtkm::Id index) const
{
vtkm::Id divisor = FacesPerCell*PointsPerCell;
vtkm::Id cellIndex = index / divisor;
vtkm::Id vertexIndex = (index % divisor) % PointsPerCell;
return PointsPerCell*cellIndex + vertexIndex;
}
};
//Returns True if the first vector argument is less than the second
//vector argument; otherwise, False
struct Id3LessThan
@ -122,146 +94,318 @@ struct ExternalFaces
}
};
//Binary operator
//Returns (a-b) mod c
class SubtractAndModulus : public vtkm::worklet::WorkletMapField
{
private:
vtkm::Id Modulus;
public:
typedef void ControlSignature(FieldIn<>, FieldIn<>, FieldOut<>);
typedef _3 ExecutionSignature(_1, _2);
VTKM_CONT
SubtractAndModulus(const vtkm::Id &c) : Modulus(c) { };
template<typename T>
VTKM_EXEC_CONT
T operator()(const T &a, const T &b) const
{
return (a - b) % Modulus;
}
};
//Worklet that returns the number of faces for each cell/shape
class NumFacesPerCell : public vtkm::worklet::WorkletMapField
class NumFacesPerCell : public vtkm::worklet::WorkletMapPointToCell
{
public:
typedef void ControlSignature(FieldIn<>, FieldOut<>);
typedef _2 ExecutionSignature(_1);
typedef void ControlSignature(CellSetIn inCellSet,
FieldOut<> numFacesInCell);
typedef _2 ExecutionSignature(CellShape);
typedef _1 InputDomain;
template<typename T>
template<typename CellShapeTag>
VTKM_EXEC
vtkm::IdComponent operator()(const T &cellType) const
vtkm::IdComponent operator()(CellShapeTag shape) const
{
return vtkm::exec::CellFaceNumberOfFaces(
vtkm::CellShapeTagGeneric(cellType), *this);
return vtkm::exec::CellFaceNumberOfFaces(shape, *this);
}
};
//Worklet that identifies the vertices of a cell face
class GetFace : public vtkm::worklet::WorkletMapPointToCell
//Worklet that identifies a cell face by 3 cononical points
class FaceHash : public vtkm::worklet::WorkletMapPointToCell
{
public:
typedef void ControlSignature(FieldInTo<AllTypes> localFaceIds,
CellSetIn cellset,
FieldOut<VecCommon> faceVertices
);
typedef void ExecutionSignature(_1, _3, CellShape, FromIndices);
typedef _2 InputDomain;
typedef void ControlSignature(CellSetIn cellset,
FieldOut<> faceHashes,
FieldOut<> originCells,
FieldOut<> originFaces);
typedef void ExecutionSignature(_2,
_3,
_4,
CellShape,
FromIndices,
InputIndex,
VisitIndex);
typedef _1 InputDomain;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT
GetFace() { }
ScatterType GetScatter() const { return this->Scatter; }
template<typename T,
typename FaceValueVecType,
typename CellShapeTag,
template<typename CountArrayType, typename Device>
VTKM_CONT
FaceHash(const CountArrayType &countArray, Device)
: Scatter(countArray, Device())
{
VTKM_IS_ARRAY_HANDLE(CountArrayType);
}
VTKM_CONT
FaceHash(const ScatterType &scatter)
: Scatter(scatter)
{ }
template<typename CellShapeTag,
typename CellNodeVecType>
VTKM_EXEC
void operator()(const T &cellFaceId,
FaceValueVecType &faceVertices,
void operator()(vtkm::Id3 &faceHash,
vtkm::Id &cellIndex,
vtkm::IdComponent &faceIndex,
CellShapeTag shape,
const CellNodeVecType &cellNodeIds) const
const CellNodeVecType &cellNodeIds,
vtkm::Id inputIndex,
vtkm::IdComponent visitIndex) const
{
vtkm::VecCConst<vtkm::IdComponent> localFaceIndices =
vtkm::exec::CellFaceLocalIndices(
static_cast<vtkm::IdComponent>(cellFaceId), shape, *this);
vtkm::exec::CellFaceLocalIndices(visitIndex, shape, *this);
if (localFaceIndices.GetNumberOfComponents() == 3)
VTKM_ASSERT(localFaceIndices.GetNumberOfComponents() >= 3);
//Assign cell points/nodes to this face
vtkm::Id faceP1 = cellNodeIds[localFaceIndices[0]];
vtkm::Id faceP2 = cellNodeIds[localFaceIndices[1]];
vtkm::Id faceP3 = cellNodeIds[localFaceIndices[2]];
//Sort the first 3 face points/nodes in ascending order
vtkm::Id sorted[3] = {faceP1, faceP2, faceP3};
vtkm::Id temp;
if (sorted[0] > sorted[2])
{
//Assign cell points/nodes to this face
vtkm::Id faceP1 = cellNodeIds[localFaceIndices[0]];
vtkm::Id faceP2 = cellNodeIds[localFaceIndices[1]];
vtkm::Id faceP3 = cellNodeIds[localFaceIndices[2]];
temp = sorted[0];
sorted[0] = sorted[2];
sorted[2] = temp;
}
if (sorted[0] > sorted[1])
{
temp = sorted[0];
sorted[0] = sorted[1];
sorted[1] = temp;
}
if (sorted[1] > sorted[2])
{
temp = sorted[1];
sorted[1] = sorted[2];
sorted[2] = temp;
}
//Sort the face points/nodes in ascending order
vtkm::Id sorted[3] = {faceP1, faceP2, faceP3};
vtkm::Id temp;
if (sorted[0] > sorted[2])
// Check the rest of the points to see if they are in the lowest 3
vtkm::IdComponent numPointsInFace =
localFaceIndices.GetNumberOfComponents();
for (vtkm::IdComponent pointIndex = 3;
pointIndex < numPointsInFace;
pointIndex++)
{
vtkm::Id nextPoint = cellNodeIds[localFaceIndices[pointIndex]];
if (nextPoint < sorted[2])
{
temp = sorted[0];
sorted[0] = sorted[2];
sorted[2] = temp;
if (nextPoint < sorted[1])
{
sorted[2] = sorted[1];
if (nextPoint < sorted[0])
{
sorted[1] = sorted[0];
sorted[0] = nextPoint;
}
else // nextPoint > P0, nextPoint < P1
{
sorted[1] = nextPoint;
}
}
else // nextPoint > P1, nextPoint < P2
{
sorted[2] = nextPoint;
}
}
if (sorted[0] > sorted[1])
else // nextPoint > P2
{
temp = sorted[0];
sorted[0] = sorted[1];
sorted[1] = temp;
}
if (sorted[1] > sorted[2])
{
temp = sorted[1];
sorted[1] = sorted[2];
sorted[2] = temp;
// Do nothing. nextPoint not in top 3.
}
}
faceVertices[0] = static_cast<T>(sorted[0]);
faceVertices[1] = static_cast<T>(sorted[1]);
faceVertices[2] = static_cast<T>(sorted[2]);
faceHash[0] = sorted[0];
faceHash[1] = sorted[1];
faceHash[2] = sorted[2];
cellIndex = inputIndex;
faceIndex = visitIndex;
}
private:
ScatterType Scatter;
};
// Worklet that identifies the number of cells written out per face, which
// is 1 for faces that belong to only one cell (external face) or 0 for
// faces that belong to more than one cell (internal face).
class FaceCounts : public vtkm::worklet::WorkletReduceByKey
{
public:
typedef void ControlSignature(KeysIn keys,
ReducedValuesOut<> numOutputCells);
typedef _2 ExecutionSignature(ValueCount);
using InputDomain = _1;
VTKM_EXEC
vtkm::IdComponent operator()(vtkm::IdComponent numCellsOnFace) const
{
if (numCellsOnFace == 1)
{
return 1;
}
else
{
// TODO: Support all face types.
this->RaiseError("Non-triangular faces not supported.");
return 0;
}
}
};
// Worklet that returns the number of points for each outputted face
class NumPointsPerFace : public vtkm::worklet::WorkletReduceByKey
{
public:
typedef void ControlSignature(KeysIn keys,
WholeCellSetIn<> inputCells,
ValuesIn<> originCells,
ValuesIn<> originFaces,
ReducedValuesOut<> numPointsInFace);
typedef _5 ExecutionSignature(_2, _3, _4);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT
ScatterType GetScatter() const { return this->Scatter; }
template<typename CountArrayType, typename Device>
VTKM_CONT
NumPointsPerFace(const CountArrayType &countArray, Device)
: Scatter(countArray, Device())
{
VTKM_IS_ARRAY_HANDLE(CountArrayType);
}
VTKM_CONT
NumPointsPerFace(const ScatterType &scatter)
: Scatter(scatter)
{ }
template<typename CellSetType,
typename OriginCellsType,
typename OriginFacesType>
VTKM_EXEC
vtkm::IdComponent operator()(const CellSetType &cellSet,
const OriginCellsType &originCells,
const OriginFacesType &originFaces) const
{
VTKM_ASSERT(originCells.GetNumberOfComponents() == 1);
VTKM_ASSERT(originFaces.GetNumberOfComponents() == 1);
return vtkm::exec::CellFaceNumberOfPoints(
originFaces[0], cellSet.GetCellShape(originCells[0]), *this);
}
private:
ScatterType Scatter;
};
// Worklet that returns the shape and connectivity for each external face
class BuildConnectivity : public vtkm::worklet::WorkletReduceByKey
{
public:
typedef void ControlSignature(KeysIn keys,
WholeCellSetIn<> inputCells,
ValuesIn<> originCells,
ValuesIn<> originFaces,
ReducedValuesOut<> shapesOut,
ReducedValuesOut<> connectivityOut);
typedef void ExecutionSignature(_2, _3, _4, _5, _6);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
VTKM_CONT
ScatterType GetScatter() const { return this->Scatter; }
template<typename CountArrayType, typename Device>
VTKM_CONT
BuildConnectivity(const CountArrayType &countArray, Device)
: Scatter(countArray, Device())
{
VTKM_IS_ARRAY_HANDLE(CountArrayType);
}
VTKM_CONT
BuildConnectivity(const ScatterType &scatter)
: Scatter(scatter)
{ }
template<typename CellSetType,
typename OriginCellsType,
typename OriginFacesType,
typename ConnectivityType>
VTKM_EXEC
void operator()(const CellSetType &cellSet,
const OriginCellsType &originCells,
const OriginFacesType &originFaces,
vtkm::UInt8 &shapeOut,
ConnectivityType &connectivityOut) const
{
VTKM_ASSERT(originCells.GetNumberOfComponents() == 1);
VTKM_ASSERT(originFaces.GetNumberOfComponents() == 1);
typename CellSetType::CellShapeTag shapeIn =
cellSet.GetCellShape(originCells[0]);
shapeOut = vtkm::exec::CellFaceShape(originFaces[0], shapeIn, *this);
vtkm::VecCConst<vtkm::IdComponent> localFaceIndices =
vtkm::exec::CellFaceLocalIndices(originFaces[0], shapeIn, *this);
vtkm::IdComponent numFacePoints =localFaceIndices.GetNumberOfComponents();
VTKM_ASSERT(numFacePoints == connectivityOut.GetNumberOfComponents());
typename CellSetType::IndicesType inCellIndices =
cellSet.GetIndices(originCells[0]);
for (vtkm::IdComponent facePointIndex = 0;
facePointIndex < numFacePoints;
facePointIndex++)
{
connectivityOut[facePointIndex] =
inCellIndices[localFaceIndices[facePointIndex]];
}
}
private:
ScatterType Scatter;
};
public:
///////////////////////////////////////////////////
/// \brief ExternalFaces: Extract Faces on outside of geometry
/// \param pointArray : Input points
/// \param pointIdArray: Input point-ids
/// \param cellToConnectivityIndexArray : Connectivity
/// \param bounds : Bounds of the input dataset
/// \param nDivisions: Number of divisions
/// \param output_pointArray: Output points
/// \param output_pointId3Array: Output point-ids
template <typename StorageT,
typename StorageU,
typename StorageV,
template <typename InCellSetType,
typename ShapeStorage,
typename NumIndicesStorage,
typename ConnectivityStorage,
typename OffsetsStorage,
typename DeviceAdapter>
void run(const vtkm::cont::ArrayHandle<vtkm::UInt8, StorageT> shapes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent, StorageU> numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id, StorageV> conn,
vtkm::cont::ArrayHandle<vtkm::UInt8, StorageT> &output_shapes,
vtkm::cont::ArrayHandle<vtkm::IdComponent, StorageU> &output_numIndices,
vtkm::cont::ArrayHandle<vtkm::Id, StorageV> &output_conn,
VTKM_CONT
void Run(const InCellSetType &inCellSet,
vtkm::cont::CellSetExplicit<
ShapeStorage,
NumIndicesStorage,
ConnectivityStorage,
OffsetsStorage> &outCellSet,
DeviceAdapter)
{
//Create a worklet to map the number of faces to each cell
vtkm::cont::ArrayHandle<vtkm::Id> facesPerCell;
vtkm::worklet::DispatcherMapField<NumFacesPerCell> numFacesDispatcher;
vtkm::cont::ArrayHandle<vtkm::IdComponent> facesPerCell;
vtkm::worklet::DispatcherMapTopology<NumFacesPerCell> numFacesDispatcher;
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
vtkm::cont::Timer<DeviceAdapter> timer;
#endif
numFacesDispatcher.Invoke(shapes, facesPerCell);
numFacesDispatcher.Invoke(inCellSet, facesPerCell);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "NumFacesPerCell_Worklet," << timer.GetElapsedTime() << "\n";
#endif
@ -269,165 +413,125 @@ public:
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
//Inclusive scan of the number of faces per cell
vtkm::cont::ArrayHandle<vtkm::Id> numFacesPrefixSum;
const vtkm::Id totalFaces =
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::ScanInclusive(facesPerCell,
numFacesPrefixSum);
vtkm::worklet::ScatterCounting
scatterCellToFace(facesPerCell, DeviceAdapter());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "ScanInclusive_Adapter," << timer.GetElapsedTime() << "\n";
std::cout << "FaceInputCount_ScatterCounting," << timer.GetElapsedTime() << "\n";
#endif
facesPerCell.ReleaseResources();
if(totalFaces == 0) return;
//Generate reverse lookup: face index to cell index
//terminate if no cells have triangles left
//For 2 tetrahedron cells with 4 faces each (array of size 8): 0,0,0,0,1,1,1,1
vtkm::cont::ArrayHandle<vtkm::Id> face2CellId;
vtkm::cont::ArrayHandle<vtkm::Id> localFaceIds;
localFaceIds.Allocate(static_cast<vtkm::Id>(totalFaces));
vtkm::cont::ArrayHandleIndex countingArray =
vtkm::cont::ArrayHandleIndex(vtkm::Id(totalFaces));
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::UpperBounds(numFacesPrefixSum,
countingArray,
face2CellId);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "UpperBounds_Adapter," << timer.GetElapsedTime() << "\n";
#endif
numFacesPrefixSum.ReleaseResources();
vtkm::worklet::DispatcherMapField<SubtractAndModulus> subtractDispatcher(SubtractAndModulus(4));
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
subtractDispatcher.Invoke(countingArray, face2CellId, localFaceIds);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "SubtractAndModulus_Worklet," << timer.GetElapsedTime() << "\n";
#endif
countingArray.ReleaseResources();
//Extract the point/vertices for each cell face
typedef vtkm::cont::ArrayHandle<vtkm::UInt8> UInt8HandleType;
typedef vtkm::cont::ArrayHandle<vtkm::IdComponent> IdCompHandleType;
typedef vtkm::cont::ArrayHandle<vtkm::Id> IdHandleType;
typedef vtkm::cont::ArrayHandleImplicit<vtkm::Id, GetConnIndex> IdImplicitType;
typedef vtkm::cont::ArrayHandlePermutation<IdHandleType, UInt8HandleType> UInt8PermutationHandleType;
typedef vtkm::cont::ArrayHandlePermutation<IdHandleType, IdCompHandleType> IdCompPermutationHandleType;
typedef vtkm::cont::ArrayHandlePermutation<IdImplicitType, IdHandleType> IdPermutationHandleType;
typedef vtkm::cont::CellSetExplicit<UInt8PermutationHandleType::StorageTag,
IdCompPermutationHandleType::StorageTag,
typename IdPermutationHandleType::StorageTag> PermutedCellSetExplicit;
UInt8PermutationHandleType pt1(face2CellId, shapes);
IdCompPermutationHandleType pt2(face2CellId, numIndices);
//Construct an augmented connectivity output array of length 4*totalFaces
//Repeat the 4 cell vertices for each cell face: 4763 4763 4763 4763 (cell 1) | 4632 4632...(cell 2)...
//First, compute indices into the original connectivity array
IdImplicitType connIndices(GetConnIndex(4, 4), 4*totalFaces);
IdPermutationHandleType faceConn(connIndices, conn);
PermutedCellSetExplicit permutedCellSet;
// Warning: This cell set is created with 0 points, which simply means that
// if you call GetNumberOfPoints it will return 0, which is of course not
// consistent with the indices. We are getting away with this because this
// is a temporary cell set that is not scheduled on points.
permutedCellSet.Fill(0, pt1, pt2, faceConn);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 3> > faceVertices;
vtkm::worklet::DispatcherMapTopology<GetFace> faceHashDispatcher;
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
faceHashDispatcher.Invoke(localFaceIds, permutedCellSet, faceVertices);
//faceVertices Output: <476> <473> <463> <763> (cell 1) | <463> <462> <432> <632> (cell 2) ...
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "GetFace_Worklet," << timer.GetElapsedTime() << "\n";
#endif
pt1.ReleaseResources();
pt2.ReleaseResources();
faceConn.ReleaseResources();
face2CellId.ReleaseResources();
localFaceIds.ReleaseResources();
connIndices.ReleaseResources();
//Sort the faces in ascending order by point/vertex indices
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Sort(faceVertices, Id3LessThan());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "Sort_Adapter," << timer.GetElapsedTime() << "\n";
#endif
//Search neighboring faces for duplicates - the internal faces
vtkm::cont::ArrayHandle<vtkm::Id3> uniqueFaceVertices;
vtkm::cont::ArrayHandle<vtkm::Id> uniqueFaceCounts;
vtkm::cont::ArrayHandle<vtkm::Id3> externalFaces;
vtkm::cont::ArrayHandleConstant<vtkm::Id> ones(1, totalFaces); //Initially all 1's
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::ReduceByKey(faceVertices,
ones,
uniqueFaceVertices,
uniqueFaceCounts,
vtkm::Add());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "ReduceByKey_Adapter," << timer.GetElapsedTime() << "\n";
#endif
ones.ReleaseResources();
faceVertices.ReleaseResources();
//Removes all faces that have counts not equal to 1 (unity)
//The faces with counts of 1 are the external faces
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::StreamCompact(uniqueFaceVertices,
uniqueFaceCounts,
externalFaces,
IsUnity());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "StreamCompact_Adapter," << timer.GetElapsedTime() << "\n";
#endif
uniqueFaceVertices.ReleaseResources();
uniqueFaceCounts.ReleaseResources();
//Generate output - the number of external faces
const vtkm::Id output_numExtFaces = externalFaces.GetNumberOfValues();
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "Total External Faces = " << output_numExtFaces << std::endl;
#endif
//Populate the output data arrays with just the external faces
//A cell set of triangle faces for tetrahedral cells
typename vtkm::cont::ArrayHandle<vtkm::Id3>::PortalConstControl extFacePortal =
externalFaces.GetPortalConstControl();
output_shapes.Allocate(output_numExtFaces);
output_numIndices.Allocate(output_numExtFaces);
output_conn.Allocate(3 * output_numExtFaces);
for(int face = 0; face < output_numExtFaces; face++)
if (scatterCellToFace.GetOutputRange(inCellSet.GetNumberOfCells()) == 0)
{
output_shapes.GetPortalControl().Set(face, vtkm::CELL_SHAPE_TRIANGLE);
output_numIndices.GetPortalControl().Set(face, static_cast<vtkm::IdComponent>(3));
output_conn.GetPortalControl().Set(3*face, extFacePortal.Get(face)[0]);
output_conn.GetPortalControl().Set(3*face + 1, extFacePortal.Get(face)[1]);
output_conn.GetPortalControl().Set(3*face + 2, extFacePortal.Get(face)[2]);
// Data has no faces. Output is empty.
outCellSet.PrepareToAddCells(0, 0);
outCellSet.CompleteAddingCells(inCellSet.GetNumberOfPoints());
return;
}
externalFaces.ReleaseResources();
//End of algorithm
vtkm::cont::ArrayHandle<vtkm::Id3> faceHashes;
vtkm::cont::ArrayHandle<vtkm::Id> originCells;
vtkm::cont::ArrayHandle<vtkm::IdComponent> originFaces;
vtkm::worklet::DispatcherMapTopology<FaceHash,DeviceAdapter>
faceHashDispatcher((FaceHash(scatterCellToFace)));
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
faceHashDispatcher.Invoke(inCellSet, faceHashes, originCells, originFaces);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "FaceHash_Worklet," << timer.GetElapsedTime() << "\n";
#endif
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::worklet::Keys<vtkm::Id3> faceKeys(faceHashes,DeviceAdapter());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "Keys_BuildArrays," << timer.GetElapsedTime() << "\n";
#endif
vtkm::cont::ArrayHandle<vtkm::IdComponent> faceOutputCount;
vtkm::worklet::DispatcherReduceByKey<FaceCounts,DeviceAdapter>
faceCountDispatcher;
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
faceCountDispatcher.Invoke(faceKeys, faceOutputCount);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "FaceCount_Worklet," << timer.GetElapsedTime() << "\n";
#endif
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::worklet::ScatterCounting
scatterCullInternalFaces(faceOutputCount, DeviceAdapter());
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "FaceOutputCount_ScatterCounting," << timer.GetElapsedTime() << "\n";
#endif
vtkm::cont::ArrayHandle<vtkm::IdComponent,NumIndicesStorage> facePointCount;
vtkm::worklet::DispatcherReduceByKey<NumPointsPerFace,DeviceAdapter>
pointsPerFaceDispatcher(scatterCullInternalFaces);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
pointsPerFaceDispatcher.Invoke(faceKeys,
inCellSet,
originCells,
originFaces,
facePointCount);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "PointsPerFaceCount_Worklet," << timer.GetElapsedTime() << "\n";
#endif
vtkm::cont::ArrayHandle<vtkm::UInt8,ShapeStorage> faceShapes;
vtkm::cont::ArrayHandle<vtkm::Id,OffsetsStorage> faceOffsets;
vtkm::Id connectivitySize;
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
vtkm::cont::ConvertNumComponentsToOffsets(
facePointCount, faceOffsets, connectivitySize);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "FacePointCount_ScanExclusive," << timer.GetElapsedTime() << "\n";
#endif
vtkm::cont::ArrayHandle<vtkm::Id,ConnectivityStorage> faceConnectivity;
// Must pre allocate because worklet invocation will not have enough
// information to.
faceConnectivity.Allocate(connectivitySize);
vtkm::worklet::DispatcherReduceByKey<BuildConnectivity,DeviceAdapter>
buildConnectivityDispatcher(scatterCullInternalFaces);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
timer.Reset();
#endif
buildConnectivityDispatcher.Invoke(
faceKeys,
inCellSet,
originCells,
originFaces,
faceShapes,
vtkm::cont::make_ArrayHandleGroupVecVariable(faceConnectivity,
faceOffsets));
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "BuildConnectivity_Worklet," << timer.GetElapsedTime() << "\n";
#endif
outCellSet.Fill(inCellSet.GetNumberOfPoints(),
faceShapes,
facePointCount,
faceConnectivity,
faceOffsets);
#ifdef __VTKM_EXTERNAL_FACES_BENCHMARK
std::cout << "Total External Faces = " << outCellSet.GetNumberOfCells() << std::endl;
#endif
}
}; //struct ExternalFaces

@ -70,10 +70,18 @@ public:
Keys()
{ }
template<typename OriginalKeyStorage, typename Device>
/// \b Construct a Keys class from an array of keys.
///
/// Given an array of keys, construct a \c Keys class that will manage
/// using these keys to perform reduce-by-key operations.
///
/// WARNING: This constructor will sort the keys array! If you need the
/// keys in the original order after calling this constructor, then make
/// a deep copy of the keys first.
///
template<typename KeyStorage, typename Device>
VTKM_CONT
Keys(const vtkm::cont::ArrayHandle<KeyType,OriginalKeyStorage> &keys,
Device)
Keys(vtkm::cont::ArrayHandle<KeyType,KeyStorage> keys, Device)
{
this->BuildArrays(keys, Device());
}
@ -150,28 +158,24 @@ private:
vtkm::cont::ArrayHandle<vtkm::Id> Offsets;
vtkm::cont::ArrayHandle<vtkm::IdComponent> Counts;
template<typename OriginalKeyArrayType, typename Device>
template<typename KeyArrayType, typename Device>
VTKM_CONT
void BuildArrays(const OriginalKeyArrayType &originalKeys, Device)
void BuildArrays(KeyArrayType &keys, Device)
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<Device>;
vtkm::Id numOriginalKeys = originalKeys.GetNumberOfValues();
vtkm::Id numKeys = keys.GetNumberOfValues();
// Copy and sort the keys. (Copy is in place.)
KeyArrayHandleType sortedKeys;
Algorithm::Copy(originalKeys, sortedKeys);
Algorithm::Copy(vtkm::cont::ArrayHandleIndex(numOriginalKeys),
Algorithm::Copy(vtkm::cont::ArrayHandleIndex(numKeys),
this->SortedValuesMap);
// TODO: Do we need the ability to specify a comparison functor for sort?
Algorithm::SortByKey(sortedKeys, this->SortedValuesMap);
Algorithm::SortByKey(keys, this->SortedValuesMap);
// Find the unique keys and the number of values per key.
Algorithm::ReduceByKey(
sortedKeys,
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(1, numOriginalKeys),
keys,
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(1, numKeys),
this->UniqueKeys,
this->Counts,
vtkm::Sum());
@ -181,7 +185,7 @@ private:
Algorithm::ScanExclusive(
vtkm::cont::make_ArrayHandleCast(this->Counts, vtkm::Id()),
this->Offsets);
VTKM_ASSERT(offsetsTotal == numOriginalKeys); // Sanity check
VTKM_ASSERT(offsetsTotal == numKeys); // Sanity check
(void)offsetsTotal; // Shut up, compiler
}
};

@ -27,6 +27,8 @@
#include <vtkm/exec/arg/BasicArg.h>
#include <vtkm/exec/arg/FetchTagExecObject.h>
#include <vtkm/exec/arg/FetchTagWholeCellSetIn.h>
#include <vtkm/exec/arg/InputIndex.h>
#include <vtkm/exec/arg/OutputIndex.h>
#include <vtkm/exec/arg/ThreadIndices.h>
#include <vtkm/exec/arg/ThreadIndicesBasic.h>
#include <vtkm/exec/arg/VisitIndex.h>
@ -88,6 +90,14 @@ public:
///
typedef vtkm::exec::arg::WorkIndex WorkIndex;
/// \c ExecutionSignature tag for getting the input index.
///
typedef vtkm::exec::arg::InputIndex InputIndex;
/// \c ExecutionSignature tag for getting the input index.
///
typedef vtkm::exec::arg::OutputIndex OutputIndex;
/// \c ExecutionSignature tag for getting the thread indices.
///
typedef vtkm::exec::arg::ThreadIndices ThreadIndices;

@ -18,61 +18,56 @@
// this software.
//============================================================================
#include <iostream>
#include <algorithm>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/internal/DeviceAdapterError.h>
#include <vtkm/io/writer/VTKDataSetWriter.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/worklet/ExternalFaces.h>
#include <algorithm>
#include <iostream>
namespace {
vtkm::cont::DataSet RunExternalFaces(vtkm::cont::DataSet &ds)
// For this test, we want using the default device adapter to be an error
// to make sure that all the code is using the device adapter we specify.
using MyDeviceAdapter = VTKM_DEFAULT_DEVICE_ADAPTER_TAG;
#undef VTKM_DEFAULT_DEVICE_ADAPTER_TAG
#define VTKM_DEFAULT_DEVICE_ADAPTER_TAG ::vtkm::cont::DeviceAdapterTagError
vtkm::cont::DataSet RunExternalFaces(vtkm::cont::DataSet &inDataSet)
{
vtkm::cont::CellSetExplicit<> cellset;
ds.GetCellSet(0).CopyTo(cellset);
vtkm::cont::CellSetExplicit<> inCellSet;
inDataSet.GetCellSet(0).CopyTo(inCellSet);
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes = cellset.GetShapesArray(
vtkm::TopologyElementTagPoint(),vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices = cellset.GetNumIndicesArray(
vtkm::TopologyElementTagPoint(),vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandle<vtkm::Id> conn = cellset.GetConnectivityArray(
vtkm::TopologyElementTagPoint(),vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandle<vtkm::UInt8> output_shapes;
vtkm::cont::ArrayHandle<vtkm::IdComponent> output_numIndices;
vtkm::cont::ArrayHandle<vtkm::Id> output_conn;
vtkm::cont::CellSetExplicit<> outCellSet("cells");
//Run the External Faces worklet
vtkm::worklet::ExternalFaces().run(
shapes,
numIndices,
conn,
output_shapes,
output_numIndices,
output_conn,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::worklet::ExternalFaces().Run(inCellSet,
outCellSet,
MyDeviceAdapter());
vtkm::cont::DataSet new_ds;
for(vtkm::IdComponent i=0; i < ds.GetNumberOfCoordinateSystems(); ++i)
vtkm::cont::DataSet outDataSet;
for(vtkm::IdComponent i=0; i < inDataSet.GetNumberOfCoordinateSystems(); ++i)
{
new_ds.AddCoordinateSystem(ds.GetCoordinateSystem(i));
outDataSet.AddCoordinateSystem(inDataSet.GetCoordinateSystem(i));
}
outDataSet.AddCellSet(outCellSet);
vtkm::cont::CellSetExplicit<> new_cs("cells");
new_cs.Fill(cellset.GetNumberOfPoints(),
output_shapes,
output_numIndices,
output_conn);
new_ds.AddCellSet(new_cs);
return new_ds;
return outDataSet;
}
void TestExternalFaces()
void TestExternalFaces1()
{
std::cout << "Test 1" << std::endl;
//--------------Construct a VTK-m Test Dataset----------------
const int nVerts = 8; //A cube that is tetrahedralized
typedef vtkm::Vec<vtkm::Float32,3> CoordType;
@ -124,11 +119,84 @@ void TestExternalFaces()
const vtkm::Id numExtFaces_actual = 12;
VTKM_TEST_ASSERT(numExtFaces_out == numExtFaces_actual, "Number of External Faces mismatch");
} // TestExternalFaces
} // TestExternalFaces1
void TestExternalFaces2()
{
std::cout << "Test 2" << std::endl;
vtkm::cont::testing::MakeTestDataSet dataSetMaker;
vtkm::cont::DataSet inDataSet = dataSetMaker.Make3DExplicitDataSet5();
// vtkm::io::writer::VTKDataSetWriter writer("vtkm_explicit_data_5.vtk");
// writer.WriteDataSet(inDataSet);
// Expected faces
const vtkm::IdComponent MAX_POINTS_PER_FACE = 4;
const vtkm::Id NUM_FACES = 12;
const vtkm::Id ExpectedExternalFaces[NUM_FACES][MAX_POINTS_PER_FACE] = {
{ 0, 3, 7, 4 },
{ 0, 1, 2, 3 },
{ 0, 4, 5, 1 },
{ 3, 2, 6, 7 },
{ 1, 5, 8, -1 },
{ 6, 2, 8, -1 },
{ 2, 1, 8, -1 },
{ 8, 10, 6, -1 },
{ 5, 10, 8, -1 },
{ 4, 7, 9, -1 },
{ 7, 6, 10, 9 },
{ 9, 10, 5, 4 }
};
vtkm::cont::DataSet outDataSet = RunExternalFaces(inDataSet);
vtkm::cont::CellSetExplicit<> outCellSet;
outDataSet.GetCellSet(0).CopyTo(outCellSet);
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == NUM_FACES,
"Got wrong number of faces.");
bool foundFaces[NUM_FACES];
for (vtkm::Id faceId = 0; faceId < NUM_FACES; faceId++)
{
foundFaces[faceId] = false;
}
for (vtkm::Id dataFaceId = 0; dataFaceId < NUM_FACES; dataFaceId++)
{
vtkm::Vec<vtkm::Id,MAX_POINTS_PER_FACE> dataIndices(-1);
outCellSet.GetIndices(dataFaceId, dataIndices);
std::cout << "Looking for face " << dataIndices << std::endl;
bool foundFace = false;
for (vtkm::Id expectedFaceId = 0;
expectedFaceId < NUM_FACES;
expectedFaceId++)
{
vtkm::Vec<vtkm::Id,MAX_POINTS_PER_FACE> expectedIndices;
vtkm::make_VecC(ExpectedExternalFaces[expectedFaceId], 4).
CopyInto(expectedIndices);
if (expectedIndices == dataIndices)
{
VTKM_TEST_ASSERT(!foundFaces[expectedFaceId], "Found face twice.");
std::cout << " found" << std::endl;
foundFace = true;
foundFaces[expectedFaceId] = true;
break;
}
}
VTKM_TEST_ASSERT(foundFace, "Face not found.");
}
}
void TestExternalFaces()
{
TestExternalFaces1();
TestExternalFaces2();
}
}
int UnitTestExternalFaces(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestExternalFaces);
return vtkm::cont::testing::Testing::Run(TestExternalFaces);
}

@ -74,7 +74,11 @@ void TryKeyType(KeyType)
vtkm::cont::ArrayHandle<KeyType> keyArray =
vtkm::cont::make_ArrayHandle(keyBuffer, ARRAY_SIZE);
vtkm::worklet::Keys<KeyType> keys(keyArray,
vtkm::cont::ArrayHandle<KeyType> sortedKeys;
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(keyArray, sortedKeys);
vtkm::worklet::Keys<KeyType> keys(sortedKeys,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
VTKM_TEST_ASSERT(keys.GetInputRange() == NUM_UNIQUE,
"Keys has bad input range.");

@ -136,7 +136,11 @@ void TryKeyType(KeyType)
vtkm::cont::ArrayHandle<KeyType> keyArray =
vtkm::cont::make_ArrayHandle(keyBuffer, ARRAY_SIZE);
vtkm::worklet::Keys<KeyType> keys(keyArray,
vtkm::cont::ArrayHandle<KeyType> sortedKeys;
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(keyArray, sortedKeys);
vtkm::worklet::Keys<KeyType> keys(sortedKeys,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::ArrayHandle<KeyType> valuesToModify;