vtk-m/vtkm/cont/testing/UnitTestArrayHandlePermutation.cxx

202 lines
6.4 KiB
C++
Raw Normal View History

2019-04-15 23:24:21 +00:00
//============================================================================
// 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.
2019-04-15 23:24:21 +00:00
//============================================================================
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/cont/testing/Testing.h>
#include <vector>
2017-05-18 14:29:41 +00:00
namespace
{
const vtkm::Id ARRAY_SIZE = 10;
2017-05-18 14:29:41 +00:00
struct DoubleIndexFunctor
{
VTKM_EXEC_CONT
2017-05-18 14:29:41 +00:00
vtkm::Id operator()(vtkm::Id index) const { return 2 * index; }
};
using DoubleIndexArrayType = vtkm::cont::ArrayHandleImplicit<DoubleIndexFunctor>;
struct CheckPermutationWorklet : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn permutationArray);
using ExecutionSignature = void(WorkIndex, _1);
template <typename T>
VTKM_EXEC void operator()(vtkm::Id index, const T& value) const
2017-05-18 14:29:41 +00:00
{
vtkm::Id permutedIndex = 2 * index;
T expectedValue = TestValue(permutedIndex, T());
2017-05-18 14:29:41 +00:00
if (!test_equal(value, expectedValue))
{
this->RaiseError("Encountered bad transformed value.");
}
}
};
struct InPlacePermutationWorklet : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldInOut permutationArray);
template <typename T>
VTKM_EXEC void operator()(T& value) const
2017-05-18 14:29:41 +00:00
{
value = value + T(1000);
}
};
2017-05-18 14:29:41 +00:00
template <typename PortalType>
VTKM_CONT void CheckInPlaceResult(PortalType portal)
{
using T = typename PortalType::ValueType;
2017-05-18 14:29:41 +00:00
for (vtkm::Id permutedIndex = 0; permutedIndex < 2 * ARRAY_SIZE; permutedIndex++)
{
2017-05-18 14:29:41 +00:00
if (permutedIndex % 2 == 0)
{
// This index was part of the permuted array; has a value changed
T expectedValue = TestValue(permutedIndex, T()) + T(1000);
2017-05-18 14:29:41 +00:00
T retrievedValue = portal.Get(permutedIndex);
VTKM_TEST_ASSERT(test_equal(expectedValue, retrievedValue), "Permuted set unexpected value.");
}
else
{
// This index was not part of the permuted array; has original value
T expectedValue = TestValue(permutedIndex, T());
2017-05-18 14:29:41 +00:00
T retrievedValue = portal.Get(permutedIndex);
VTKM_TEST_ASSERT(test_equal(expectedValue, retrievedValue),
"Permuted array modified value it should not have.");
}
}
}
struct OutputPermutationWorklet : vtkm::worklet::WorkletMapField
{
// Note: Using a FieldOut for the input domain is rare (and mostly discouraged),
// but it works as long as the array is allocated to the size desired.
using ControlSignature = void(FieldOut permutationArray);
using ExecutionSignature = void(WorkIndex, _1);
template <typename T>
VTKM_EXEC void operator()(vtkm::Id index, T& value) const
2017-05-18 14:29:41 +00:00
{
value = TestValue(static_cast<vtkm::Id>(index), T());
}
};
2017-05-18 14:29:41 +00:00
template <typename PortalType>
VTKM_CONT void CheckOutputResult(PortalType portal)
{
using T = typename PortalType::ValueType;
2017-05-18 14:29:41 +00:00
for (vtkm::IdComponent permutedIndex = 0; permutedIndex < 2 * ARRAY_SIZE; permutedIndex++)
{
2017-05-18 14:29:41 +00:00
if (permutedIndex % 2 == 0)
{
// This index was part of the permuted array; has a value changed
2017-05-18 14:29:41 +00:00
vtkm::Id originalIndex = permutedIndex / 2;
T expectedValue = TestValue(originalIndex, T());
2017-05-18 14:29:41 +00:00
T retrievedValue = portal.Get(permutedIndex);
VTKM_TEST_ASSERT(test_equal(expectedValue, retrievedValue), "Permuted set unexpected value.");
}
else
{
// This index was not part of the permuted array; has original value
T expectedValue = TestValue(permutedIndex, T());
2017-05-18 14:29:41 +00:00
T retrievedValue = portal.Get(permutedIndex);
VTKM_TEST_ASSERT(test_equal(expectedValue, retrievedValue),
"Permuted array modified value it should not have.");
}
}
}
2017-05-18 14:29:41 +00:00
template <typename ValueType>
struct PermutationTests
{
using IndexArrayType = vtkm::cont::ArrayHandleImplicit<DoubleIndexFunctor>;
using ValueArrayType = vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagBasic>;
using PermutationArrayType = vtkm::cont::ArrayHandlePermutation<IndexArrayType, ValueArrayType>;
2017-05-18 14:29:41 +00:00
ValueArrayType MakeValueArray() const
{
// Allocate a buffer and set initial values
2017-05-18 14:29:41 +00:00
std::vector<ValueType> buffer(2 * ARRAY_SIZE);
for (vtkm::IdComponent index = 0; index < 2 * ARRAY_SIZE; index++)
{
vtkm::UInt32 i = static_cast<vtkm::UInt32>(index);
buffer[i] = TestValue(index, ValueType());
}
// Create an ArrayHandle from the buffer
Improvements to moving data into ArrayHandle We have made several improvements to adding data into an `ArrayHandle`. ## Moving data from an `std::vector` For numerous reasons, it is convenient to define data in a `std::vector` and then wrap that into an `ArrayHandle`. It is often the case that an `std::vector` is filled and then becomes unused once it is converted to an `ArrayHandle`. In this case, what we really want is to pass the data off to the `ArrayHandle` so that the `ArrayHandle` is now managing the data and not the `std::vector`. C++11 has a mechanism to do this: move semantics. You can now pass variables to functions as an "rvalue" (right-hand value). When something is passed as an rvalue, it can pull state out of that variable and move it somewhere else. `std::vector` implements this movement so that an rvalue can be moved to another `std::vector` without actually copying the data. `make_ArrayHandle` now also takes advantage of this feature to move rvalue `std::vector`s. There is a special form of `make_ArrayHandle` named `make_ArrayHandleMove` that takes an rvalue. There is also a special overload of `make_ArrayHandle` itself that handles an rvalue `vector`. (However, using the explicit move version is better if you want to make sure the data is actually moved.) ## Make `ArrayHandle` from initalizer list A common use case for using `std::vector` (particularly in our unit tests) is to quickly add an initalizer list into an `ArrayHandle`. Now you can by simply passing an initializer list to `make_ArrayHandle`. ## Deprecated `make_ArrayHandle` with default shallow copy For historical reasons, passing an `std::vector` or a pointer to `make_ArrayHandle` does a shallow copy (i.e. `CopyFlag` defaults to `Off`). Although more efficient, this mode is inherintly unsafe, and making it the default is asking for trouble. To combat this, calling `make_ArrayHandle` without a copy flag is deprecated. In this way, if you wish to do the faster but more unsafe creation of an `ArrayHandle` you should explicitly express that. This requried quite a few changes through the VTK-m source (particularly in the tests). ## Similar changes to `Field` `vtkm::cont::Field` has a `make_Field` helper function that is similar to `make_ArrayHandle`. It also features the ability to create fields from `std::vector`s and C arrays. It also likewise had the same unsafe behavior by default of not copying from the source of the arrays. That behavior has similarly been depreciated. You now have to specify a copy flag. The ability to construct a `Field` from an initializer list of values has also been added.
2020-07-16 16:32:32 +00:00
return vtkm::cont::make_ArrayHandle(buffer, vtkm::CopyFlag::On);
}
void operator()() const
{
std::cout << "Create ArrayHandlePermutation" << std::endl;
IndexArrayType indexArray(DoubleIndexFunctor(), ARRAY_SIZE);
ValueArrayType valueArray = this->MakeValueArray();
PermutationArrayType permutationArray(indexArray, valueArray);
VTKM_TEST_ASSERT(permutationArray.GetNumberOfValues() == ARRAY_SIZE,
"Permutation array wrong size.");
VTKM_TEST_ASSERT(permutationArray.WritePortal().GetNumberOfValues() == ARRAY_SIZE,
2017-05-18 14:29:41 +00:00
"Permutation portal wrong size.");
VTKM_TEST_ASSERT(permutationArray.ReadPortal().GetNumberOfValues() == ARRAY_SIZE,
2017-05-18 14:29:41 +00:00
"Permutation portal wrong size.");
vtkm::cont::Invoker invoke;
std::cout << "Test initial values in execution environment" << std::endl;
invoke(CheckPermutationWorklet{}, permutationArray);
std::cout << "Try in place operation" << std::endl;
invoke(InPlacePermutationWorklet{}, permutationArray);
CheckInPlaceResult(valueArray.WritePortal());
CheckInPlaceResult(valueArray.ReadPortal());
std::cout << "Try output operation" << std::endl;
invoke(OutputPermutationWorklet{}, permutationArray);
CheckOutputResult(valueArray.ReadPortal());
CheckOutputResult(valueArray.WritePortal());
}
};
struct TryInputType
{
2017-05-18 14:29:41 +00:00
template <typename InputType>
void operator()(InputType) const
{
PermutationTests<InputType>()();
}
};
void TestArrayHandlePermutation()
{
vtkm::testing::Testing::TryTypes(TryInputType(), vtkm::TypeListCommon());
}
} // anonymous namespace
int UnitTestArrayHandlePermutation(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestArrayHandlePermutation, argc, argv);
}