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