diff --git a/vtkm/cont/ArrayHandleCompositeVector.h b/vtkm/cont/ArrayHandleCompositeVector.h new file mode 100644 index 000000000..b205d819d --- /dev/null +++ b/vtkm/cont/ArrayHandleCompositeVector.h @@ -0,0 +1,716 @@ +//============================================================================ +// 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 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. 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_ArrayHandleCompositeVector_h +#define vtk_m_ArrayHandleCompositeVector_h + +#include +#include +#include + +#include + +#include + +#include + +namespace vtkm { +namespace cont { + +namespace internal { + +namespace detail { + +template +struct CompositeVectorSwizzleFunctor +{ + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + typedef vtkm::Tuple ComponentMapType; + + // Caution! This is a reference. + const ComponentMapType &SourceComponents; + + VTKM_EXEC_CONT_EXPORT + CompositeVectorSwizzleFunctor(const ComponentMapType &sourceComponents) + : SourceComponents(sourceComponents) { } + + // Currently only supporting 1-4 components. + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, const T2 &p2) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, const T2 &p2, const T3 &p3) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1]), + vtkm::VectorTraits::GetComponent(p3, this->SourceComponents[2])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, + const T2 &p2, + const T3 &p3, + const T4 &p4) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1]), + vtkm::VectorTraits::GetComponent(p3, this->SourceComponents[2]), + vtkm::VectorTraits::GetComponent(p4, this->SourceComponents[3])); + } +}; + +template +struct CompositeVectorPullValueFunctor +{ + vtkm::Id Index; + + VTKM_EXEC_EXPORT + CompositeVectorPullValueFunctor(vtkm::Id index) : Index(index) { } + + // This form is to pull values out of array arguments. + template + VTKM_EXEC_EXPORT + typename PortalType::ValueType operator()(const PortalType &portal) const { + return portal.Get(this->Index); + } + + // This form is an identity to pass the return value back. + VTKM_EXEC_EXPORT + const ReturnValueType &operator()(const ReturnValueType &value) const { + return value; + } +}; + +struct CompositeVectorArrayToPortalCont { + template + struct ReturnType { + typedef typename ArrayHandleType::PortalConstControl type; + }; + + template + VTKM_CONT_EXPORT + typename ReturnType::type + operator()(const ArrayHandleType &array) const { + return array.GetPortalConstControl(); + } +}; + +template +struct CompositeVectorArrayToPortalExec { + template + struct ReturnType { + typedef typename ArrayHandleType::template ExecutionTypes< + DeviceAdapterTag>::PortalConst type; + }; + + template + VTKM_CONT_EXPORT + typename ReturnType::type + operator()(const ArrayHandleType &array) const { + return array.PrepareForInput(DeviceAdapterTag()); + } +}; + +struct CheckArraySizeFunctor { + vtkm::Id ExpectedSize; + CheckArraySizeFunctor(vtkm::Id expectedSize) : ExpectedSize(expectedSize) { } + + template + void operator()(const T &a) const { + if (a.GetNumberOfValues() != this->ExpectedSize) + { + throw vtkm::cont::ErrorControlBadValue( + "All input arrays to ArrayHandleCompositeVector must be the same size."); + } + } +}; + +} // namespace detail + +/// \brief A portal that gets values from components of other portals. +/// +/// This is the portal used within ArrayHandleCompositeVector. +/// +template +class ArrayPortalCompositeVector +{ + typedef vtkm::internal::FunctionInterface PortalTypes; + typedef vtkm::Tuple ComponentMapType; + +public: + typedef typename PortalTypes::ResultType ValueType; + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + + BOOST_STATIC_ASSERT(NUM_COMPONENTS == PortalTypes::ARITY); + + VTKM_EXEC_CONT_EXPORT + ArrayPortalCompositeVector() { } + + VTKM_CONT_EXPORT + ArrayPortalCompositeVector( + const PortalTypes portals, + vtkm::Tuple sourceComponents) + : Portals(portals), SourceComponents(sourceComponents) { } + + VTKM_EXEC_EXPORT + vtkm::Id GetNumberOfValues() const { + return this->Portals.template GetParameter<1>().GetNumberOfValues(); + } + + VTKM_EXEC_EXPORT + ValueType Get(vtkm::Id index) const { + // This might be inefficient because we are copying all the portals only + // because they are coupled with the return value. + PortalTypes localPortals = this->Portals; + localPortals.InvokeExec( + detail::CompositeVectorSwizzleFunctor(this->SourceComponents), + detail::CompositeVectorPullValueFunctor(index)); + return localPortals.GetReturnValue(); + } + +private: + PortalTypes Portals; + ComponentMapType SourceComponents; +}; + +/// \brief A "portal" that holds arrays to get components from. +/// +/// This class takes place as the control-side portal within an +/// ArrayHandleCompositeVector. This is an incomplete implementation, so you +/// really can't use it to get values. However, between this and the +/// specialization ArrayTransfer, it's enough to get values to the execution +/// environment. +/// +template +class ArrayPortalCompositeVectorCont +{ + typedef vtkm::internal::FunctionInterface + FunctionInterfaceArrays; + +public: + typedef typename FunctionInterfaceArrays::ResultType ValueType; + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + typedef vtkm::Tuple ComponentMapType; + + // If you get a compile error here, it means you probably tried to create + // an ArrayHandleCompositeVector with a return type of a vector with a + // different number of components than the number of arrays given. + BOOST_STATIC_ASSERT(NUM_COMPONENTS == FunctionInterfaceArrays::ARITY); + + VTKM_CONT_EXPORT + ArrayPortalCompositeVectorCont() : NumberOfValues(0) { } + + VTKM_CONT_EXPORT + ArrayPortalCompositeVectorCont( + const FunctionInterfaceArrays &arrays, + const ComponentMapType &vtkmNotUsed(sourceComponents)) + : NumberOfValues(arrays.template GetParameter<1>().GetNumberOfValues()) { } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + return this->NumberOfValues; + } + + VTKM_CONT_EXPORT + ValueType Get(vtkm::Id vtkmNotUsed(index)) const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + VTKM_CONT_EXPORT + void Set(vtkm::Id vtkmNotUsed(index), ValueType vtkmNotUsed(value)) { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + // Not a viable type, but there is no implementation. + typedef ValueType *IteratorType; + + VTKM_CONT_EXPORT + IteratorType GetIteratorBegin() const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + VTKM_CONT_EXPORT + IteratorType GetIteratorEnd() const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + +private: + vtkm::Id NumberOfValues; +}; + +template +struct ArrayContainerControlTagCompositeVector { }; + +/// A convenience class that provides a typedef to the appropriate tag for +/// a counting array container. +template +struct ArrayHandleCompositeVectorTraits +{ + typedef vtkm::cont::internal::ArrayContainerControlTagCompositeVector< + SignatureWithArrays> Tag; + typedef typename vtkm::internal::FunctionInterface::ResultType + ValueType; + typedef vtkm::cont::internal::ArrayContainerControl< + ValueType, Tag> ContainerType; +}; + +// It may seem weird that this specialization throws an exception for +// everything, but that is because all the functionality is handled in the +// ArrayTransfer class. +template +class ArrayContainerControl< + typename ArrayHandleCompositeVectorTraits::ValueType, + vtkm::cont::internal::ArrayContainerControlTagCompositeVector > +{ + typedef vtkm::internal::FunctionInterface + FunctionInterfaceWithArrays; + static const int NUM_COMPONENTS = FunctionInterfaceWithArrays::ARITY; + typedef vtkm::Tuple ComponentMapType; + +public: + typedef ArrayPortalCompositeVectorCont PortalType; + typedef PortalType PortalConstType; + typedef typename PortalType::ValueType ValueType; + + VTKM_CONT_EXPORT + ArrayContainerControl() : Valid(false) { } + + VTKM_CONT_EXPORT + ArrayContainerControl(const FunctionInterfaceWithArrays &arrays, + const ComponentMapType &sourceComponents) + : Arrays(arrays), SourceComponents(sourceComponents), Valid(true) + { + arrays.ForEachCont( + detail::CheckArraySizeFunctor(this->GetNumberOfValues())); + } + + VTKM_CONT_EXPORT + PortalType GetPortal() { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read only."); + } + + VTKM_CONT_EXPORT + PortalConstType GetPortalConst() const { + if (!this->Valid) + { + throw vtkm::cont::ErrorControlBadValue( + "Tried to use an ArrayHandleCompositeHandle without dependent arrays."); + } + return PortalConstType(this->Arrays, this->SourceComponents); + } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + if (!this->Valid) + { + throw vtkm::cont::ErrorControlBadValue( + "Tried to use an ArrayHandleCompositeHandle without dependent arrays."); + } + return this->Arrays.template GetParameter<1>().GetNumberOfValues(); + } + + VTKM_CONT_EXPORT + void Allocate(vtkm::Id vtkmNotUsed(numberOfValues)) { + throw vtkm::cont::ErrorControlInternal( + + "The allocate method for the composite vector control array " + "container should never have been called. The allocate is generally " + "only called by the execution array manager, and the array transfer " + "for the transform container should prevent the execution array " + "manager from being directly used."); + } + + VTKM_CONT_EXPORT + void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read-only."); + } + + VTKM_CONT_EXPORT + void ReleaseResources() { + if (this->Valid) + { + // TODO: Implement this. + } + } + + VTKM_CONT_EXPORT + const FunctionInterfaceWithArrays &GetArrays() const { + VTKM_ASSERT_CONT(this->Valid); + return this->Arrays; + } + + VTKM_CONT_EXPORT + const ComponentMapType &GetSourceComponents() const { + VTKM_ASSERT_CONT(this->Valid); + return this->SourceComponents; + } + +private: + FunctionInterfaceWithArrays Arrays; + ComponentMapType SourceComponents; + bool Valid; +}; + +template +class ArrayTransfer< + typename ArrayHandleCompositeVectorTraits::ValueType, + vtkm::cont::internal::ArrayContainerControlTagCompositeVector, + DeviceAdapterTag> +{ + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + + typedef typename ArrayHandleCompositeVectorTraits::ContainerType + ContainerType; + + typedef vtkm::internal::FunctionInterface + FunctionWithArrays; + typedef typename FunctionWithArrays::template StaticTransformType< + detail::CompositeVectorArrayToPortalExec >::type + FunctionWithPortals; + typedef typename FunctionWithPortals::Signature SignatureWithPortals; + +public: + typedef typename ArrayHandleCompositeVectorTraits::ValueType + ValueType; + + // These are not currently fully implemented. + typedef typename ContainerType::PortalType PortalControl; + typedef typename ContainerType::PortalConstType PortalConstControl; + + typedef ArrayPortalCompositeVector PortalExecution; + typedef ArrayPortalCompositeVector PortalConstExecution; + + VTKM_CONT_EXPORT + ArrayTransfer() : ContainerValid(false) { } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + VTKM_ASSERT_CONT(this->ContainerValid); + return this->Container.GetNumberOfValues(); + } + + VTKM_CONT_EXPORT + void LoadDataForInput(PortalConstControl vtkmNotUsed(contPortal)) + { + throw vtkm::cont::ErrorControlInternal( + "ArrayHandleCompositeVector in a bad state. " + "There must be a UserArray set, but how did that happen?"); + } + + VTKM_CONT_EXPORT + void LoadDataForInput(const ContainerType &controlArray) + { + this->Container = controlArray; + this->ContainerValid = true; + } + + VTKM_CONT_EXPORT + void LoadDataForInPlace(ContainerType &vtkmNotUsed(controlArray)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output or in place."); + } + + VTKM_CONT_EXPORT + void AllocateArrayForOutput(ContainerType &vtkmNotUsed(controlArray), + vtkm::Id vtkmNotUsed(numberOfValues)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output."); + } + + VTKM_CONT_EXPORT + void RetrieveOutputData(ContainerType &vtkmNotUsed(controlArray)) const + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output."); + } + + template + VTKM_CONT_EXPORT + void CopyInto(IteratorTypeControl vtkmNotUsed(dest)) const + { + throw vtkm::cont::ErrorControlInternal( + "CopyInto not implemented for composite vector arrays."); + } + + VTKM_CONT_EXPORT + void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be resized."); + } + + VTKM_CONT_EXPORT + PortalExecution GetPortalExecution() + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read-only. (Get the const portal.)"); + } + + VTKM_CONT_EXPORT + PortalConstExecution GetPortalConstExecution() const + { + VTKM_ASSERT_CONT(this->ContainerValid); + return + PortalConstExecution( + this->Container.GetArrays().StaticTransformCont( + detail::CompositeVectorArrayToPortalExec()), + this->Container.GetSourceComponents()); + } + + VTKM_CONT_EXPORT + void ReleaseResources() { + this->Container.ReleaseResources(); + } + +private: + bool ContainerValid; + ContainerType Container; +}; + +} // namespace internal + +/// \brief An \c ArrayHandle that combines components from other arrays. +/// +/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that +/// derives its content from other arrays. It takes up to 4 other \c +/// ArrayHandle objects and mimics an array that contains vectors with +/// components that come from these delegate arrays. +/// +/// The easiest way to create and type an \c ArrayHandleCompositeVector is +/// to use the \c make_ArrayHandleCompositeVector functions. +/// +template +class ArrayHandleCompositeVector + : public vtkm::cont::ArrayHandle< + typename internal::ArrayHandleCompositeVectorTraits::ValueType, + typename internal::ArrayHandleCompositeVectorTraits::Tag> +{ + typedef typename internal::ArrayHandleCompositeVectorTraits::ContainerType + ArrayContainerControlType; + typedef typename internal::ArrayPortalCompositeVectorCont::ComponentMapType + ComponentMapType; + +public: + typedef vtkm::cont::ArrayHandle< + typename internal::ArrayHandleCompositeVectorTraits::ValueType, + typename internal::ArrayHandleCompositeVectorTraits::Tag> + Superclass; + typedef typename Superclass::ValueType ValueType; + + VTKM_CONT_EXPORT + ArrayHandleCompositeVector() : Superclass() { } + + VTKM_CONT_EXPORT + ArrayHandleCompositeVector( + const vtkm::internal::FunctionInterface &arrays, + const ComponentMapType &sourceComponents) + : Superclass(ArrayContainerControlType(arrays, sourceComponents)) + { } + + /// Template constructors for passing in types. You'll get weird compile + /// errors if the argument types do not actually match the types in the + /// signature. + /// + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface(array1), + ComponentMapType(sourceComponent1))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2), + ComponentMapType(sourceComponent1, + sourceComponent2))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2, + const ArrayHandleType3 &array3, + int sourceComponent3) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2, array3), + ComponentMapType(sourceComponent1, + sourceComponent2, + sourceComponent3))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2, + const ArrayHandleType3 &array3, + int sourceComponent3, + const ArrayHandleType4 &array4, + int sourceComponent4) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2, array3, array4), + ComponentMapType(sourceComponent1, + sourceComponent2, + sourceComponent3, + sourceComponent4))) + { } +}; + +/// Create a composite vector array from other arrays. +/// +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + typename vtkm::VectorTraits::ComponentType( + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1) +{ + return ArrayHandleCompositeVector< + typename vtkm::VectorTraits::ComponentType( + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,2>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,2>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,3>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2, + const vtkm::cont::ArrayHandle &array3, + int sourceComponent3) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,3>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2, + array3, + sourceComponent3); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,4>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2, + const vtkm::cont::ArrayHandle &array3, + int sourceComponent3, + const vtkm::cont::ArrayHandle &array4, + int sourceComponent4) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,4>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2, + array3, + sourceComponent3, + array4, + sourceComponent4); +} + +} +} // namespace vtkm::cont + +#endif //vtk_m_ArrayHandleCompositeVector_h diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 69722e9f8..42b62f338 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -25,6 +25,7 @@ set(headers ArrayContainerControlBasic.h ArrayContainerControlImplicit.h ArrayHandle.h + ArrayHandleCompositeVector.h ArrayHandleCounting.h ArrayHandleUniformPointCoordinates.h ArrayPortal.h diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index 8b4064ca8..a953a8253 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -29,6 +29,7 @@ set(unit_tests UnitTestArrayContainerControlBasic.cxx UnitTestArrayContainerControlImplicit.cxx UnitTestArrayHandle.cxx + UnitTestArrayHandleCompositeVector.cxx UnitTestArrayHandleCounting.cxx UnitTestArrayHandleUniformPointCoordinates.cxx UnitTestContTesting.cxx diff --git a/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx b/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx new file mode 100644 index 000000000..6d1512d4a --- /dev/null +++ b/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx @@ -0,0 +1,313 @@ +//============================================================================ +// 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 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. 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. +//============================================================================ + +// Make sure ArrayHandleCompositeVector does not rely on default container or +// device adapter. +#define VTKM_ARRAY_CONTAINER_CONTROL VTKM_ARRAY_CONTAINER_CONTROL_ERROR +#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_ERROR + +#include + +#include + +#include +#include + +#include + +#include + +namespace { + +const vtkm::Id ARRAY_SIZE = 10; + +typedef vtkm::cont::ArrayContainerControlTagBasic Container; + +vtkm::Scalar TestValue(vtkm::Id index, int inComponentIndex, int inArrayId) +{ + return index + vtkm::Scalar(0.1)*inComponentIndex + vtkm::Scalar(0.01)*inArrayId; +} + +template +vtkm::cont::ArrayHandle +MakeInputArray(int arrayId) +{ + typedef vtkm::VectorTraits VTraits; + + // Create a buffer with valid test values. + ValueType buffer[ARRAY_SIZE]; + for (vtkm::Id index = 0; index < ARRAY_SIZE; index++) + { + for (int componentIndex = 0; + componentIndex < VTraits::NUM_COMPONENTS; + componentIndex++) + { + VTraits::SetComponent(buffer[index], + componentIndex, + TestValue(index, componentIndex, arrayId)); + } + } + + // Make an array handle that points to this buffer. + typedef vtkm::cont::ArrayHandle ArrayHandleType; + ArrayHandleType bufferHandle = + vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, Container()); + + // When this function returns, the array is going to go out of scope, which + // will invalidate the array handle we just created. So copy to a new buffer + // that will stick around after we return. + ArrayHandleType copyHandle; + vtkm::cont::DeviceAdapterAlgorithm::Copy( + bufferHandle, copyHandle); + + return copyHandle; +} + +template +void CheckArray(const vtkm::cont::ArrayHandle &outArray, + const int *inComponents, + const int *inArrayIds) +{ + // ArrayHandleCompositeVector currently does not implement the ability to + // get to values on the control side, so copy to an array that is accessible. + typedef vtkm::cont::ArrayHandle ArrayHandleType; + ArrayHandleType arrayCopy; + vtkm::cont::DeviceAdapterAlgorithm::Copy( + outArray, arrayCopy); + + typename ArrayHandleType::PortalConstControl portal = + arrayCopy.GetPortalConstControl(); + typedef vtkm::VectorTraits VTraits; + for (vtkm::Id index = 0; index < ARRAY_SIZE; index++) + { + ValueType retreivedValue = portal.Get(index); + for (int componentIndex = 0; + componentIndex < VTraits::NUM_COMPONENTS; + componentIndex++) + { + vtkm::Scalar retrievedComponent = + VTraits::GetComponent(retreivedValue, componentIndex); + vtkm::Scalar expectedComponent = TestValue(index, + inComponents[componentIndex], + inArrayIds[componentIndex]); + VTKM_TEST_ASSERT(retrievedComponent == expectedComponent, + "Got bad value."); + } + } +} + +template +void TryScalarArray() +{ + std::cout << "Creating a scalar array from one of " + << inComponents << " components." << std::endl; + + typedef vtkm::Tuple InValueType; + typedef vtkm::cont::ArrayHandle InArrayType; + int inArrayId = 0; + InArrayType inArray = MakeInputArray(inArrayId); + + typedef vtkm::cont::ArrayHandleCompositeVector + OutArrayType; + for (int inComponentIndex = 0; + inComponentIndex < inComponents; + inComponentIndex++) + { + OutArrayType outArray = + vtkm::cont::make_ArrayHandleCompositeVector(inArray, inComponentIndex); + CheckArray(outArray, &inComponentIndex, &inArrayId); + } +} + +template +void TryVector4(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2, + vtkm::cont::ArrayHandle array3, + vtkm::cont::ArrayHandle array4) +{ + int arrayIds[4] = {0, 1, 2, 3}; + int inComponents[4]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + for (inComponents[2] = 0; + inComponents[2] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[2]++) + { + for (inComponents[3] = 0; + inComponents[3] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[3]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1], + array3, inComponents[2], + array4, inComponents[3]), + inComponents, + arrayIds); + } + } + } + } +} + +template +void TryVector3(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2, + vtkm::cont::ArrayHandle array3) +{ + int arrayIds[3] = {0, 1, 2}; + int inComponents[3]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + for (inComponents[2] = 0; + inComponents[2] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[2]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1], + array3, inComponents[2]), + inComponents, + arrayIds); + } + } + } + + std::cout << " Fourth component from Scalar." << std::endl; + TryVector4(array1, array2, array3, MakeInputArray(3)); + std::cout << " Fourth component from Vector4." << std::endl; + TryVector4(array1, array2, array3, MakeInputArray(3)); +} + +template +void TryVector2(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2) +{ + int arrayIds[2] = {0, 1}; + int inComponents[2]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1]), + inComponents, + arrayIds); + } + } + + std::cout << " Third component from Scalar." << std::endl; + TryVector3(array1, array2, MakeInputArray(2)); + std::cout << " Third component from Vector2." << std::endl; + TryVector3(array1, array2, MakeInputArray(2)); +} + +template +void TryVector1(vtkm::cont::ArrayHandle array1) +{ + int arrayIds[1] = {0}; + int inComponents[1]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector(array1, inComponents[0]), + inComponents, + arrayIds); + } + + std::cout << " Second component from Scalar." << std::endl; + TryVector2(array1, MakeInputArray(1)); + std::cout << " Second component from Vector4." << std::endl; + TryVector2(array1, MakeInputArray(1)); +} + +void TryVector() +{ + std::cout << "Trying many permutations of composite vectors." << std::endl; + + std::cout << " First component from Scalar." << std::endl; + TryVector1(MakeInputArray(0)); + std::cout << " First component from Vector3." << std::endl; + TryVector1(MakeInputArray(0)); +} + +void TestBadArrayLengths() { + std::cout << "Checking behavior when size of input arrays do not agree." + << std::endl; + + typedef vtkm::cont::ArrayHandle InArrayType; + InArrayType longInArray = MakeInputArray(0); + InArrayType shortInArray = MakeInputArray(1); + shortInArray.Shrink(ARRAY_SIZE/2); + + try + { + vtkm::cont::make_ArrayHandleCompositeVector(longInArray,0, shortInArray,0); + VTKM_TEST_FAIL("Did not get exception like expected."); + } + catch (vtkm::cont::ErrorControlBadValue error) + { + std::cout << "Got expected error: " << std::endl + << error.GetMessage() << std::endl; + } +} + +void TestCompositeVector() { + TryScalarArray<2>(); + TryScalarArray<3>(); + TryScalarArray<4>(); + + TryVector(); + + TestBadArrayLengths(); +} + +} // anonymous namespace + +int UnitTestArrayHandleCompositeVector(int, char *[]) +{ + return vtkm::cont::testing::Testing::Run(TestCompositeVector); +}