1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 #include <vtkm/worklet/MaskIndices.h>
11
12 #include <vtkm/cont/ArrayCopy.h>
13 #include <vtkm/cont/ArrayHandle.h>
14 #include <vtkm/cont/ArrayHandleConstant.h>
15 #include <vtkm/cont/testing/MakeTestDataSet.h>
16 #include <vtkm/cont/testing/Testing.h>
17 #include <vtkm/worklet/DispatcherMapTopology.h>
18 #include <vtkm/worklet/WorkletMapTopology.h>
19
20 #include <ctime>
21 #include <random>
22
23 namespace
24 {
25
26 class Worklet : public vtkm::worklet::WorkletVisitPointsWithCells
27 {
28 public:
29 using ControlSignature = void(CellSetIn cellset, FieldInOutPoint outPointId);
30 using ExecutionSignature = void(InputIndex, _2);
31 using InputDomain = _1;
32
33 using MaskType = vtkm::worklet::MaskIndices;
34
operator ()(vtkm::Id pointId,vtkm::Id & outPointId) const35 VTKM_EXEC void operator()(vtkm::Id pointId, vtkm::Id& outPointId) const { outPointId = pointId; }
36 };
37
38 template <typename CellSetType>
RunTest(const CellSetType & cellset,const vtkm::cont::ArrayHandle<vtkm::Id> & indices)39 void RunTest(const CellSetType& cellset, const vtkm::cont::ArrayHandle<vtkm::Id>& indices)
40 {
41 vtkm::Id numPoints = cellset.GetNumberOfPoints();
42 vtkm::cont::ArrayHandle<vtkm::Id> outPointId;
43 vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleConstant<vtkm::Id>(-1, numPoints), outPointId);
44
45 vtkm::worklet::DispatcherMapTopology<Worklet> dispatcher(vtkm::worklet::MaskIndices{ indices });
46 dispatcher.Invoke(cellset, outPointId);
47
48 vtkm::cont::ArrayHandle<vtkm::Int8> stencil;
49 vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleConstant<vtkm::Int8>(0, numPoints), stencil);
50
51 // Check that output that should be written was.
52 for (vtkm::Id i = 0; i < indices.GetNumberOfValues(); ++i)
53 {
54 // All unmasked indices should have been copied to the output.
55 vtkm::Id unMaskedIndex = indices.ReadPortal().Get(i);
56 vtkm::Id writtenValue = outPointId.ReadPortal().Get(unMaskedIndex);
57 VTKM_TEST_ASSERT(unMaskedIndex == writtenValue,
58 "Did not pass unmasked index. Expected ",
59 unMaskedIndex,
60 ". Got ",
61 writtenValue);
62
63 // Mark index as passed.
64 stencil.WritePortal().Set(unMaskedIndex, 1);
65 }
66
67 // Check that output that should not be written was not.
68 for (vtkm::Id i = 0; i < numPoints; ++i)
69 {
70 if (stencil.ReadPortal().Get(i) == 0)
71 {
72 vtkm::Id foundValue = outPointId.ReadPortal().Get(i);
73 VTKM_TEST_ASSERT(foundValue == -1,
74 "Expected index ",
75 i,
76 " to be unwritten but was filled with ",
77 foundValue);
78 }
79 }
80 }
81
TestMaskIndices()82 void TestMaskIndices()
83 {
84 vtkm::cont::DataSet dataset = vtkm::cont::testing::MakeTestDataSet().Make2DUniformDataSet0();
85 auto cellset = dataset.GetCellSet();
86 vtkm::Id numberOfPoints = cellset.GetNumberOfPoints();
87
88 vtkm::UInt32 seed = static_cast<vtkm::UInt32>(std::time(nullptr));
89
90 std::default_random_engine generator;
91 generator.seed(seed);
92 std::uniform_int_distribution<vtkm::Id> countDistribution(1, 2 * numberOfPoints);
93 std::uniform_int_distribution<vtkm::Id> ptidDistribution(0, numberOfPoints - 1);
94
95 const int iterations = 5;
96 std::cout << "Testing with random indices " << iterations << " times\n";
97 std::cout << "Seed: " << seed << std::endl;
98 for (int i = 1; i <= iterations; ++i)
99 {
100 std::cout << "iteration: " << i << "\n";
101
102 vtkm::Id count = countDistribution(generator);
103 vtkm::cont::ArrayHandle<vtkm::Id> indices;
104 indices.Allocate(count);
105
106 // Note that it is possible that the same index will be written twice, which is generally
107 // a bad idea with MaskIndices. However, the worklet will write the same value for each
108 // instance, so we should still get the correct result.
109 {
110 auto portal = indices.WritePortal();
111 std::cout << "using indices:";
112 for (vtkm::Id j = 0; j < count; ++j)
113 {
114 auto val = ptidDistribution(generator);
115 std::cout << " " << val;
116 portal.Set(j, val);
117 }
118 std::cout << "\n";
119 }
120
121 RunTest(cellset, indices);
122 }
123 }
124
125 } // anonymous namespace
126
UnitTestMaskIndices(int argc,char * argv[])127 int UnitTestMaskIndices(int argc, char* argv[])
128 {
129 return vtkm::cont::testing::Testing::Run(TestMaskIndices, argc, argv);
130 }
131