//============================================================================ // 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. //============================================================================ #ifndef vtk_m_cont_testing_TestingFancyArrayHandles_h #define vtk_m_cont_testing_TestingFancyArrayHandles_h #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace fancy_array_detail { template struct IndexSquared { VTKM_EXEC_CONT ValueType operator()(vtkm::Id index) const { using ComponentType = typename vtkm::VecTraits::ComponentType; return ValueType(static_cast(index * index)); } }; template struct ValueSquared { template VTKM_EXEC_CONT ValueType operator()(U u) const { return vtkm::Dot(u, u); } }; struct ValueScale { ValueScale() : Factor(1.0) { } ValueScale(vtkm::Float64 factor) : Factor(factor) { } template VTKM_EXEC_CONT ValueType operator()(const ValueType& v) const { using Traits = vtkm::VecTraits; using TTraits = vtkm::TypeTraits; using ComponentType = typename Traits::ComponentType; ValueType result = TTraits::ZeroInitialization(); for (vtkm::IdComponent i = 0; i < Traits::GetNumberOfComponents(v); ++i) { vtkm::Float64 vi = static_cast(Traits::GetComponent(v, i)); vtkm::Float64 ri = vi * this->Factor; Traits::SetComponent(result, i, static_cast(ri)); } return result; } private: vtkm::Float64 Factor; }; struct InverseValueScale { InverseValueScale() : InverseFactor(1.0) { } InverseValueScale(vtkm::Float64 factor) : InverseFactor(1.0 / factor) { } template VTKM_EXEC_CONT ValueType operator()(const ValueType& v) const { using Traits = vtkm::VecTraits; using TTraits = vtkm::TypeTraits; using ComponentType = typename Traits::ComponentType; ValueType result = TTraits::ZeroInitialization(); for (vtkm::IdComponent i = 0; i < Traits::GetNumberOfComponents(v); ++i) { vtkm::Float64 vi = static_cast(Traits::GetComponent(v, i)); vtkm::Float64 ri = vi * this->InverseFactor; Traits::SetComponent(result, i, static_cast(ri)); } return result; } private: vtkm::Float64 InverseFactor; }; template struct VirtualTransformFunctorBase : public vtkm::VirtualObjectBase { VirtualTransformFunctorBase() = default; VTKM_EXEC_CONT virtual ValueType operator()(const ValueType& v) const = 0; }; template struct VirtualTransformFunctor : VirtualTransformFunctorBase { FunctorType Functor; VTKM_CONT VirtualTransformFunctor(const FunctorType& functor) : Functor(functor) { } VTKM_EXEC_CONT ValueType operator()(const ValueType& v) const override { return this->Functor(v); } }; template struct TransformExecObject : public vtkm::cont::ExecutionAndControlObjectBase { vtkm::cont::VirtualObjectHandle> VirtualFunctor; VTKM_CONT TransformExecObject() = default; template VTKM_CONT TransformExecObject(const FunctorType& functor) { // Need to make sure the serial device is supported, since that is what is used on the // control side. Therefore we reset to all supported devices. vtkm::cont::ScopedRuntimeDeviceTracker scopedTracker( vtkm::cont::DeviceAdapterTagSerial{}, vtkm::cont::RuntimeDeviceTrackerMode::Enable); this->VirtualFunctor.Reset(new VirtualTransformFunctor(functor)); } struct FunctorWrapper { const VirtualTransformFunctorBase* FunctorPointer; FunctorWrapper() = default; VTKM_CONT FunctorWrapper(const VirtualTransformFunctorBase* functorPointer) : FunctorPointer(functorPointer) { } template VTKM_EXEC ValueType operator()(const InValueType& value) const { return (*this->FunctorPointer)(value); } }; template VTKM_CONT FunctorWrapper PrepareForExecution(DeviceAdapterTag device) const { return FunctorWrapper(this->VirtualFunctor.PrepareForExecution(device)); } VTKM_CONT FunctorWrapper PrepareForControl() const { return FunctorWrapper(this->VirtualFunctor.Get()); } }; } namespace vtkm { namespace cont { namespace testing { /// This class has a single static member, Run, that tests that all Fancy Array /// Handles work with the given DeviceAdapter /// template struct TestingFancyArrayHandles { private: static const int ARRAY_SIZE = 10; public: struct PassThrough : public vtkm::worklet::WorkletMapField { using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = _2(_1); template VTKM_EXEC ValueType operator()(const ValueType& inValue) const { return inValue; } }; struct InplaceFunctorPair : public vtkm::worklet::WorkletMapField { using ControlSignature = void(FieldInOut); using ExecutionSignature = void(_1); template VTKM_EXEC void operator()(vtkm::Pair& value) const { value.second = value.first; } }; #ifndef VTKM_CUDA private: #endif struct TestCompositeAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const ValueType value = TestValue(13, ValueType()); std::vector compositeData(ARRAY_SIZE, value); vtkm::cont::ArrayHandle compositeInput = vtkm::cont::make_ArrayHandle(compositeData); auto composite = vtkm::cont::make_ArrayHandleCompositeVector(compositeInput, compositeInput, compositeInput); vtkm::cont::printSummary_ArrayHandle(composite, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle> result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(composite, result); //verify that the control portal works for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i) { const vtkm::Vec result_v = result.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, vtkm::Vec(value)), "CompositeVector Handle Failed"); const vtkm::Vec result_c = composite.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_c, vtkm::Vec(value)), "CompositeVector Handle Failed"); } } }; struct TestConstantAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const ValueType value = TestValue(43, ValueType()); vtkm::cont::ArrayHandleConstant constant = vtkm::cont::make_ArrayHandleConstant(value, ARRAY_SIZE); vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(constant, result); vtkm::cont::printSummary_ArrayHandle(constant, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); const ValueType control_value = constant.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, value), "Counting Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Counting Handle Control Failed"); } } }; struct TestCountingAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using ComponentType = typename vtkm::VecTraits::ComponentType; const vtkm::Id length = ARRAY_SIZE; //need to initialize the start value or else vectors will have //random values to start ComponentType component_value(0); const ValueType start = ValueType(component_value); vtkm::cont::ArrayHandleCounting counting = vtkm::cont::make_ArrayHandleCounting(start, ValueType(1), length); vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(counting, result); vtkm::cont::printSummary_ArrayHandle(counting, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); const ValueType correct_value = ValueType(component_value); const ValueType control_value = counting.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Counting Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Counting Handle Control Failed"); component_value = ComponentType(component_value + ComponentType(1)); } } }; struct TestImplicitAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using FunctorType = ::fancy_array_detail::IndexSquared; FunctorType functor; vtkm::cont::ArrayHandleImplicit implicit = vtkm::cont::make_ArrayHandleImplicit(functor, length); vtkm::cont::printSummary_ArrayHandle(implicit, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(implicit, result); //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); const ValueType correct_value = functor(i); const ValueType control_value = implicit.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Implicit Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Implicit Handle Failed"); } } }; struct TestConcatenateAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using FunctorType = ::fancy_array_detail::IndexSquared; using ComponentType = typename vtkm::VecTraits::ComponentType; using ValueHandleType = vtkm::cont::ArrayHandleImplicit; using BasicArrayType = vtkm::cont::ArrayHandle; using ConcatenateType = vtkm::cont::ArrayHandleConcatenate; FunctorType functor; for (vtkm::Id start_pos = 0; start_pos < length; start_pos += length / 4) { vtkm::Id implicitLen = length - start_pos; vtkm::Id basicLen = start_pos; // make an implicit array ValueHandleType implicit = vtkm::cont::make_ArrayHandleImplicit(functor, implicitLen); // make a basic array std::vector basicVec; for (vtkm::Id i = 0; i < basicLen; i++) { basicVec.push_back(ValueType(static_cast(i))); basicVec.push_back(ValueType(ComponentType(i))); } BasicArrayType basic = vtkm::cont::make_ArrayHandle(basicVec); // concatenate two arrays together ConcatenateType concatenate = vtkm::cont::make_ArrayHandleConcatenate(implicit, basic); vtkm::cont::printSummary_ArrayHandle(concatenate, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(concatenate, result); //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); ValueType correct_value; if (i < implicitLen) correct_value = implicit.GetPortalConstControl().Get(i); else correct_value = basic.GetPortalConstControl().Get(i - implicitLen); const ValueType control_value = concatenate.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "ArrayHandleConcatenate as Input Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "ArrayHandleConcatenate as Input Failed"); } } } }; struct TestPermutationAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using FunctorType = ::fancy_array_detail::IndexSquared; using KeyHandleType = vtkm::cont::ArrayHandleCounting; using ValueHandleType = vtkm::cont::ArrayHandleImplicit; using PermutationHandleType = vtkm::cont::ArrayHandlePermutation; FunctorType functor; for (vtkm::Id start_pos = 0; start_pos < length; start_pos += length / 4) { const vtkm::Id counting_length = length - start_pos; KeyHandleType counting = vtkm::cont::make_ArrayHandleCounting(start_pos, 1, counting_length); ValueHandleType implicit = vtkm::cont::make_ArrayHandleImplicit(functor, length); PermutationHandleType permutation = vtkm::cont::make_ArrayHandlePermutation(counting, implicit); vtkm::cont::printSummary_ArrayHandle(permutation, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(permutation, result); //verify that the control portal works for (vtkm::Id i = 0; i < counting_length; ++i) { const vtkm::Id value_index = i; const vtkm::Id key_index = start_pos + i; const ValueType result_v = result.GetPortalConstControl().Get(value_index); const ValueType correct_value = implicit.GetPortalConstControl().Get(key_index); const ValueType control_value = permutation.GetPortalConstControl().Get(value_index); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Implicit Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Implicit Handle Failed"); } } } }; struct TestViewAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using FunctorType = ::fancy_array_detail::IndexSquared; using ValueHandleType = vtkm::cont::ArrayHandleImplicit; using ViewHandleType = vtkm::cont::ArrayHandleView; FunctorType functor; for (vtkm::Id start_pos = 0; start_pos < length; start_pos += length / 4) { const vtkm::Id counting_length = length - start_pos; ValueHandleType implicit = vtkm::cont::make_ArrayHandleImplicit(functor, length); ViewHandleType view = vtkm::cont::make_ArrayHandleView(implicit, start_pos, counting_length); vtkm::cont::printSummary_ArrayHandle(view, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(view, result); //verify that the control portal works for (vtkm::Id i = 0; i < counting_length; ++i) { const vtkm::Id value_index = i; const vtkm::Id key_index = start_pos + i; const ValueType result_v = result.GetPortalConstControl().Get(value_index); const ValueType correct_value = implicit.GetPortalConstControl().Get(key_index); const ValueType control_value = view.GetPortalConstControl().Get(value_index); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Implicit Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Implicit Handle Failed"); } } } }; struct TestTransformAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using FunctorType = fancy_array_detail::ValueScale; const vtkm::Id length = ARRAY_SIZE; FunctorType functor(2.0); vtkm::cont::ArrayHandle input; vtkm::cont::ArrayHandleTransform, FunctorType> transformed = vtkm::cont::make_ArrayHandleTransform(input, functor); input.Allocate(length); SetPortal(input.GetPortalControl()); vtkm::cont::printSummary_ArrayHandle(transformed, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(transformed, result); //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); const ValueType correct_value = functor(TestValue(i, ValueType())); const ValueType control_value = transformed.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Transform Handle Control Failed"); } } }; struct TestTransformVirtualAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using FunctorType = fancy_array_detail::ValueScale; using VirtualFunctorType = fancy_array_detail::TransformExecObject; const vtkm::Id length = ARRAY_SIZE; FunctorType functor(2.0); VirtualFunctorType virtualFunctor(functor); vtkm::cont::ArrayHandle input; auto transformed = vtkm::cont::make_ArrayHandleTransform(input, virtualFunctor); input.Allocate(length); SetPortal(input.GetPortalControl()); vtkm::cont::printSummary_ArrayHandle(transformed, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(transformed, result); //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = result.GetPortalConstControl().Get(i); const ValueType correct_value = functor(TestValue(i, ValueType())); const ValueType control_value = transformed.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Transform Handle Control Failed"); } } }; struct TestCountingTransformAsInput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using ComponentType = typename vtkm::VecTraits::ComponentType; using OutputValueType = ComponentType; using FunctorType = fancy_array_detail::ValueSquared; vtkm::Id length = ARRAY_SIZE; FunctorType functor; //need to initialize the start value or else vectors will have //random values to start ComponentType component_value(0); const ValueType start = ValueType(component_value); vtkm::cont::ArrayHandleCounting counting(start, ValueType(1), length); vtkm::cont::ArrayHandleTransform, FunctorType> countingTransformed = vtkm::cont::make_ArrayHandleTransform(counting, functor); vtkm::cont::printSummary_ArrayHandle(countingTransformed, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(countingTransformed, result); //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const OutputValueType result_v = result.GetPortalConstControl().Get(i); const OutputValueType correct_value = functor(ValueType(component_value)); const OutputValueType control_value = countingTransformed.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Counting Handle Failed"); VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Transform Counting Handle Control Failed"); component_value = ComponentType(component_value + ComponentType(1)); } } }; struct TestCastAsInput { template VTKM_CONT void operator()(CastToType vtkmNotUsed(type)) const { using InputArrayType = vtkm::cont::ArrayHandleIndex; InputArrayType input(ARRAY_SIZE); vtkm::cont::ArrayHandleCast castArray = vtkm::cont::make_ArrayHandleCast(input, CastToType()); vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(castArray, result); vtkm::cont::printSummary_ArrayHandle(castArray, std::cout); std::cout << std::endl; // verify results vtkm::Id length = ARRAY_SIZE; for (vtkm::Id i = 0; i < length; ++i) { VTKM_TEST_ASSERT(result.GetPortalConstControl().Get(i) == static_cast(input.GetPortalConstControl().Get(i)), "Casting ArrayHandle Failed"); } } }; struct TestCastAsOutput { template VTKM_CONT void operator()(CastFromType vtkmNotUsed(type)) const { using InputArrayType = vtkm::cont::ArrayHandleIndex; using ResultArrayType = vtkm::cont::ArrayHandle; InputArrayType input(ARRAY_SIZE); ResultArrayType result; vtkm::cont::ArrayHandleCast castArray = vtkm::cont::make_ArrayHandleCast(result); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, castArray); vtkm::cont::printSummary_ArrayHandle(castArray, std::cout); std::cout << std::endl; // verify results vtkm::Id length = ARRAY_SIZE; for (vtkm::Id i = 0; i < length; ++i) { VTKM_TEST_ASSERT(input.GetPortalConstControl().Get(i) == static_cast(result.GetPortalConstControl().Get(i)), "Casting ArrayHandle Failed"); } } }; template struct TestGroupVecAsInput { template VTKM_CONT void operator()(ComponentType) const { using ValueType = vtkm::Vec; ComponentType testValues[ARRAY_SIZE * NUM_COMPONENTS]; for (vtkm::Id index = 0; index < ARRAY_SIZE * NUM_COMPONENTS; ++index) { testValues[index] = TestValue(index, ComponentType()); } vtkm::cont::ArrayHandle baseArray = vtkm::cont::make_ArrayHandle(testValues, ARRAY_SIZE * NUM_COMPONENTS); vtkm::cont::ArrayHandleGroupVec, NUM_COMPONENTS> groupArray(baseArray); VTKM_TEST_ASSERT(groupArray.GetNumberOfValues() == ARRAY_SIZE, "Group array reporting wrong array size."); vtkm::cont::printSummary_ArrayHandle(groupArray, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle resultArray; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(groupArray, resultArray); VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE, "Got bad result array size."); //verify that the control portal works vtkm::Id totalIndex = 0; for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index) { const ValueType result = resultArray.GetPortalConstControl().Get(index); for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) { const ComponentType expectedValue = TestValue(totalIndex, ComponentType()); VTKM_TEST_ASSERT(test_equal(result[componentIndex], expectedValue), "Result array got wrong value."); totalIndex++; } } } }; template struct TestGroupVecAsOutput { template VTKM_CONT void operator()(ComponentType) const { using ValueType = vtkm::Vec; vtkm::cont::ArrayHandle baseArray; baseArray.Allocate(ARRAY_SIZE); SetPortal(baseArray.GetPortalControl()); vtkm::cont::ArrayHandle resultArray; vtkm::cont::ArrayHandleGroupVec, NUM_COMPONENTS> groupArray(resultArray); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(baseArray, groupArray); vtkm::cont::printSummary_ArrayHandle(groupArray, std::cout); std::cout << std::endl; vtkm::cont::printSummary_ArrayHandle(resultArray, std::cout); std::cout << std::endl; VTKM_TEST_ASSERT(groupArray.GetNumberOfValues() == ARRAY_SIZE, "Group array reporting wrong array size."); VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE * NUM_COMPONENTS, "Got bad result array size."); //verify that the control portal works vtkm::Id totalIndex = 0; for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index) { const ValueType expectedValue = TestValue(index, ValueType()); for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) { const ComponentType result = resultArray.GetPortalConstControl().Get(totalIndex); VTKM_TEST_ASSERT(test_equal(result, expectedValue[componentIndex]), "Result array got wrong value."); totalIndex++; } } } }; // GroupVecVariable is a bit strange because it supports values of different // lengths, so a simple pass through worklet will not work. Use custom // worklets. struct GroupVariableInputWorklet : public vtkm::worklet::WorkletMapField { using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, WorkIndex, _2); template VTKM_EXEC void operator()(const InputType& input, vtkm::Id workIndex, vtkm::Id& dummyOut) const { using ComponentType = typename InputType::ComponentType; vtkm::IdComponent expectedSize = static_cast(workIndex + 1); if (expectedSize != input.GetNumberOfComponents()) { this->RaiseError("Got unexpected number of components."); } vtkm::Id valueIndex = workIndex * (workIndex + 1) / 2; dummyOut = valueIndex; for (vtkm::IdComponent componentIndex = 0; componentIndex < expectedSize; componentIndex++) { ComponentType expectedValue = TestValue(valueIndex, ComponentType()); if (vtkm::Abs(expectedValue - input[componentIndex]) > 0.000001) { this->RaiseError("Got bad value in GroupVariableInputWorklet."); } valueIndex++; } } }; struct TestGroupVecVariableAsInput { template VTKM_CONT void operator()(ComponentType) const { vtkm::Id sourceArraySize; vtkm::cont::ArrayHandleCounting numComponentsArray(1, 1, ARRAY_SIZE); vtkm::cont::ArrayHandle offsetsArray = vtkm::cont::ConvertNumComponentsToOffsets(numComponentsArray, sourceArraySize); vtkm::cont::ArrayHandle sourceArray; sourceArray.Allocate(sourceArraySize); SetPortal(sourceArray.GetPortalControl()); vtkm::cont::printSummary_ArrayHandle( vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetsArray), std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle dummyArray; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetsArray), dummyArray); dummyArray.GetPortalConstControl(); } }; // GroupVecVariable is a bit strange because it supports values of different // lengths, so a simple pass through worklet will not work. Use custom // worklets. struct GroupVariableOutputWorklet : public vtkm::worklet::WorkletMapField { using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_2, WorkIndex); template VTKM_EXEC void operator()(OutputType& output, vtkm::Id workIndex) const { using ComponentType = typename OutputType::ComponentType; vtkm::IdComponent expectedSize = static_cast(workIndex + 1); if (expectedSize != output.GetNumberOfComponents()) { this->RaiseError("Got unexpected number of components."); } vtkm::Id valueIndex = workIndex * (workIndex + 1) / 2; for (vtkm::IdComponent componentIndex = 0; componentIndex < expectedSize; componentIndex++) { output[componentIndex] = TestValue(valueIndex, ComponentType()); valueIndex++; } } }; struct TestGroupVecVariableAsOutput { template VTKM_CONT void operator()(ComponentType) const { vtkm::Id sourceArraySize; vtkm::cont::ArrayHandleCounting numComponentsArray(1, 1, ARRAY_SIZE); vtkm::cont::ArrayHandle offsetsArray = vtkm::cont::ConvertNumComponentsToOffsets( numComponentsArray, sourceArraySize, DeviceAdapterTag()); vtkm::cont::ArrayHandle sourceArray; sourceArray.Allocate(sourceArraySize); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetsArray)); vtkm::cont::printSummary_ArrayHandle( vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetsArray), std::cout); std::cout << std::endl; vtkm::cont::printSummary_ArrayHandle(sourceArray, std::cout); std::cout << std::endl; CheckPortal(sourceArray.GetPortalConstControl()); } }; struct TestZipAsInput { template VTKM_CONT void operator()(vtkm::Pair vtkmNotUsed(pair)) const { using PairType = vtkm::Pair; using KeyComponentType = typename vtkm::VecTraits::ComponentType; using ValueComponentType = typename vtkm::VecTraits::ComponentType; KeyType testKeys[ARRAY_SIZE]; ValueType testValues[ARRAY_SIZE]; for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i) { testKeys[i] = KeyType(static_cast(ARRAY_SIZE - i)); testValues[i] = ValueType(static_cast(i)); } vtkm::cont::ArrayHandle keys = vtkm::cont::make_ArrayHandle(testKeys, ARRAY_SIZE); vtkm::cont::ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues, ARRAY_SIZE); vtkm::cont::ArrayHandleZip, vtkm::cont::ArrayHandle> zip = vtkm::cont::make_ArrayHandleZip(keys, values); vtkm::cont::printSummary_ArrayHandle(zip, std::cout); std::cout << std::endl; vtkm::cont::ArrayHandle result; vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(zip, result); //verify that the control portal works for (int i = 0; i < ARRAY_SIZE; ++i) { const PairType result_v = result.GetPortalConstControl().Get(i); const PairType correct_value(KeyType(static_cast(ARRAY_SIZE - i)), ValueType(static_cast(i))); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "ArrayHandleZip Failed as input"); } } }; struct TestDiscardAsOutput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using DiscardHandleType = vtkm::cont::ArrayHandleDiscard; using ComponentType = typename vtkm::VecTraits::ComponentType; using Portal = typename vtkm::cont::ArrayHandle::PortalControl; const vtkm::Id length = ARRAY_SIZE; vtkm::cont::ArrayHandle input; input.Allocate(length); Portal inputPortal = input.GetPortalControl(); for (vtkm::Id i = 0; i < length; ++i) { inputPortal.Set(i, ValueType(ComponentType(i))); } DiscardHandleType discard; discard.Allocate(length); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, discard); // No output to verify since none is stored in memory. Just checking that // this compiles/runs without errors. } }; struct TestPermutationAsOutput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using KeyHandleType = vtkm::cont::ArrayHandleCounting; using ValueHandleType = vtkm::cont::ArrayHandle; using PermutationHandleType = vtkm::cont::ArrayHandlePermutation; using ComponentType = typename vtkm::VecTraits::ComponentType; vtkm::cont::ArrayHandle input; using Portal = typename vtkm::cont::ArrayHandle::PortalControl; input.Allocate(length); Portal inputPortal = input.GetPortalControl(); for (vtkm::Id i = 0; i < length; ++i) { inputPortal.Set(i, ValueType(ComponentType(i))); } ValueHandleType values; values.Allocate(length * 2); KeyHandleType counting = vtkm::cont::make_ArrayHandleCounting(length, 1, length); PermutationHandleType permutation = vtkm::cont::make_ArrayHandlePermutation(counting, values); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, permutation); vtkm::cont::printSummary_ArrayHandle(permutation, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = permutation.GetPortalConstControl().Get(i); const ValueType correct_value = ValueType(ComponentType(i)); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Permutation Handle Failed As Output"); } } }; struct TestViewAsOutput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { const vtkm::Id length = ARRAY_SIZE; using ValueHandleType = vtkm::cont::ArrayHandle; using ViewHandleType = vtkm::cont::ArrayHandleView; using ComponentType = typename vtkm::VecTraits::ComponentType; vtkm::cont::ArrayHandle input; using Portal = typename vtkm::cont::ArrayHandle::PortalControl; input.Allocate(length); Portal inputPortal = input.GetPortalControl(); for (vtkm::Id i = 0; i < length; ++i) { inputPortal.Set(i, ValueType(ComponentType(i))); } ValueHandleType values; values.Allocate(length * 2); ViewHandleType view = vtkm::cont::make_ArrayHandleView(values, length, length); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, view); vtkm::cont::printSummary_ArrayHandle(view, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = view.GetPortalConstControl().Get(i); const ValueType correct_value = ValueType(ComponentType(i)); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Permutation Handle Failed As Output"); } } }; struct TestTransformAsOutput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using FunctorType = fancy_array_detail::ValueScale; using InverseFunctorType = fancy_array_detail::InverseValueScale; const vtkm::Id length = ARRAY_SIZE; FunctorType functor(2.0); InverseFunctorType inverseFunctor(2.0); vtkm::cont::ArrayHandle input; input.Allocate(length); SetPortal(input.GetPortalControl()); vtkm::cont::ArrayHandle output; auto transformed = vtkm::cont::make_ArrayHandleTransform(output, functor, inverseFunctor); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, transformed); vtkm::cont::printSummary_ArrayHandle(transformed, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = output.GetPortalConstControl().Get(i); const ValueType correct_value = inverseFunctor(TestValue(i, ValueType())); const ValueType control_value = transformed.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed"); VTKM_TEST_ASSERT(test_equal(functor(result_v), control_value), "Transform Handle Control Failed"); } } }; struct TestTransformVirtualAsOutput { template VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const { using FunctorType = fancy_array_detail::ValueScale; using InverseFunctorType = fancy_array_detail::InverseValueScale; using VirtualFunctorType = fancy_array_detail::TransformExecObject; const vtkm::Id length = ARRAY_SIZE; FunctorType functor(2.0); InverseFunctorType inverseFunctor(2.0); VirtualFunctorType virtualFunctor(functor); VirtualFunctorType virtualInverseFunctor(inverseFunctor); vtkm::cont::ArrayHandle input; input.Allocate(length); SetPortal(input.GetPortalControl()); vtkm::cont::ArrayHandle output; auto transformed = vtkm::cont::make_ArrayHandleTransform(output, virtualFunctor, virtualInverseFunctor); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, transformed); vtkm::cont::printSummary_ArrayHandle(transformed, std::cout); std::cout << std::endl; //verify that the control portal works for (vtkm::Id i = 0; i < length; ++i) { const ValueType result_v = output.GetPortalConstControl().Get(i); const ValueType correct_value = inverseFunctor(TestValue(i, ValueType())); const ValueType control_value = transformed.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed"); VTKM_TEST_ASSERT(test_equal(functor(result_v), control_value), "Transform Handle Control Failed"); } } }; struct TestZipAsOutput { template VTKM_CONT void operator()(vtkm::Pair vtkmNotUsed(pair)) const { using PairType = vtkm::Pair; using KeyComponentType = typename vtkm::VecTraits::ComponentType; using ValueComponentType = typename vtkm::VecTraits::ComponentType; PairType testKeysAndValues[ARRAY_SIZE]; for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i) { testKeysAndValues[i] = PairType(KeyType(static_cast(ARRAY_SIZE - i)), ValueType(static_cast(i))); } vtkm::cont::ArrayHandle input = vtkm::cont::make_ArrayHandle(testKeysAndValues, ARRAY_SIZE); vtkm::cont::ArrayHandle result_keys; vtkm::cont::ArrayHandle result_values; vtkm::cont::ArrayHandleZip, vtkm::cont::ArrayHandle> result_zip = vtkm::cont::make_ArrayHandleZip(result_keys, result_values); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(input, result_zip); vtkm::cont::printSummary_ArrayHandle(result_zip, std::cout); std::cout << std::endl; //now the two arrays we have zipped should have data inside them for (int i = 0; i < ARRAY_SIZE; ++i) { const KeyType result_key = result_keys.GetPortalConstControl().Get(i); const ValueType result_value = result_values.GetPortalConstControl().Get(i); VTKM_TEST_ASSERT( test_equal(result_key, KeyType(static_cast(ARRAY_SIZE - i))), "ArrayHandleZip Failed as input for key"); VTKM_TEST_ASSERT(test_equal(result_value, ValueType(static_cast(i))), "ArrayHandleZip Failed as input for value"); } } }; struct TestZipAsInPlace { template VTKM_CONT void operator()(ValueType) const { vtkm::cont::ArrayHandle inputValues; inputValues.Allocate(ARRAY_SIZE); SetPortal(inputValues.GetPortalControl()); vtkm::cont::ArrayHandle outputValues; outputValues.Allocate(ARRAY_SIZE); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(vtkm::cont::make_ArrayHandleZip(inputValues, outputValues)); vtkm::cont::printSummary_ArrayHandle(outputValues, std::cout); std::cout << std::endl; CheckPortal(outputValues.GetPortalConstControl()); } }; struct ScalarTypesToTest : vtkm::ListTagBase { }; struct ZipTypesToTest : vtkm::ListTagBase, vtkm::Pair, vtkm::Pair> { }; struct HandleTypesToTest : vtkm::ListTagBase { }; struct CastTypesToTest : vtkm::ListTagBase { }; struct TestAll { VTKM_CONT void operator()() const { std::cout << "Doing FancyArrayHandle tests" << std::endl; std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleCompositeVector as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestCompositeAsInput(), ScalarTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleConstant as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestConstantAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleCounting as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestCountingAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleImplicit as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestImplicitAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandlePermutation as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestPermutationAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleView as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestViewAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleTransform as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestTransformAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleTransform with virtual as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestTransformVirtualAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleTransform with Counting as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestCountingTransformAsInput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleCast as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestCastAsInput(), CastTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleCast as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestCastAsOutput(), CastTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecAsInput<3>(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVec<4> as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecAsInput<4>(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVec<2> as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecAsOutput<2>(), ScalarTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVec<3> as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecAsOutput<3>(), ScalarTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVecVariable as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecVariableAsInput(), ScalarTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleGroupVecVariable as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestGroupVecVariableAsOutput(), ScalarTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleZip as Input" << std::endl; vtkm::testing::Testing::TryTypes(TestingFancyArrayHandles::TestZipAsInput(), ZipTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandlePermutation as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestPermutationAsOutput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleView as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestViewAsOutput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleTransform as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestTransformAsOutput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleTransform with virtual as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestTransformVirtualAsOutput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleDiscard as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestDiscardAsOutput(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleZip as Output" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestZipAsOutput(), ZipTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleZip as In Place" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestZipAsInPlace(), HandleTypesToTest()); std::cout << "-------------------------------------------" << std::endl; std::cout << "Testing ArrayHandleConcatenate as Input" << std::endl; vtkm::testing::Testing::TryTypes( TestingFancyArrayHandles::TestConcatenateAsInput(), HandleTypesToTest()); } }; public: /// Run a suite of tests to check to see if a DeviceAdapter properly supports /// all the fancy array handles that vtkm supports. Returns an /// error code that can be returned from the main function of a test. /// static VTKM_CONT int Run(int argc, char* argv[]) { vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(DeviceAdapterTag()); return vtkm::cont::testing::Testing::Run(TestAll(), argc, argv); } }; } } } // namespace vtkm::cont::testing #endif //vtk_m_cont_testing_TestingFancyArrayHandles_h