Created ArrayHandleCompositeVector.

This derived array handle creates an array of vectors whose components come
from other arrays of vectors. In either case ArrayHandleCompositeVector
handles scalars as vectors of size 1.
This commit is contained in:
Kenneth Moreland 2014-05-05 09:24:03 -06:00
parent 3f2099fe76
commit 261157ed22
4 changed files with 1031 additions and 0 deletions

@ -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 <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ErrorControlBadValue.h>
#include <vtkm/cont/ErrorControlInternal.h>
#include <vtkm/VectorTraits.h>
#include <vtkm/internal/FunctionInterface.h>
#include <boost/static_assert.hpp>
namespace vtkm {
namespace cont {
namespace internal {
namespace detail {
template<typename ValueType>
struct CompositeVectorSwizzleFunctor
{
static const int NUM_COMPONENTS =
vtkm::VectorTraits<ValueType>::NUM_COMPONENTS;
typedef vtkm::Tuple<int, NUM_COMPONENTS> 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<typename T1>
VTKM_EXEC_CONT_EXPORT
ValueType operator()(const T1 &p1) const {
return ValueType(
vtkm::VectorTraits<T1>::GetComponent(p1, this->SourceComponents[0]));
}
template<typename T1, typename T2>
VTKM_EXEC_CONT_EXPORT
ValueType operator()(const T1 &p1, const T2 &p2) const {
return ValueType(
vtkm::VectorTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VectorTraits<T2>::GetComponent(p2, this->SourceComponents[1]));
}
template<typename T1, typename T2, typename T3>
VTKM_EXEC_CONT_EXPORT
ValueType operator()(const T1 &p1, const T2 &p2, const T3 &p3) const {
return ValueType(
vtkm::VectorTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VectorTraits<T2>::GetComponent(p2, this->SourceComponents[1]),
vtkm::VectorTraits<T3>::GetComponent(p3, this->SourceComponents[2]));
}
template<typename T1, typename T2, typename T3, typename T4>
VTKM_EXEC_CONT_EXPORT
ValueType operator()(const T1 &p1,
const T2 &p2,
const T3 &p3,
const T4 &p4) const {
return ValueType(
vtkm::VectorTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VectorTraits<T2>::GetComponent(p2, this->SourceComponents[1]),
vtkm::VectorTraits<T3>::GetComponent(p3, this->SourceComponents[2]),
vtkm::VectorTraits<T4>::GetComponent(p4, this->SourceComponents[3]));
}
};
template<typename ReturnValueType>
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<typename PortalType>
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<typename ArrayHandleType>
struct ReturnType {
typedef typename ArrayHandleType::PortalConstControl type;
};
template<typename ArrayHandleType>
VTKM_CONT_EXPORT
typename ReturnType<ArrayHandleType>::type
operator()(const ArrayHandleType &array) const {
return array.GetPortalConstControl();
}
};
template<typename DeviceAdapterTag>
struct CompositeVectorArrayToPortalExec {
template<typename ArrayHandleType>
struct ReturnType {
typedef typename ArrayHandleType::template ExecutionTypes<
DeviceAdapterTag>::PortalConst type;
};
template<typename ArrayHandleType>
VTKM_CONT_EXPORT
typename ReturnType<ArrayHandleType>::type
operator()(const ArrayHandleType &array) const {
return array.PrepareForInput(DeviceAdapterTag());
}
};
struct CheckArraySizeFunctor {
vtkm::Id ExpectedSize;
CheckArraySizeFunctor(vtkm::Id expectedSize) : ExpectedSize(expectedSize) { }
template<typename T>
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<typename SignatureWithPortals>
class ArrayPortalCompositeVector
{
typedef vtkm::internal::FunctionInterface<SignatureWithPortals> PortalTypes;
typedef vtkm::Tuple<int, PortalTypes::ARITY> ComponentMapType;
public:
typedef typename PortalTypes::ResultType ValueType;
static const int NUM_COMPONENTS =
vtkm::VectorTraits<ValueType>::NUM_COMPONENTS;
BOOST_STATIC_ASSERT(NUM_COMPONENTS == PortalTypes::ARITY);
VTKM_EXEC_CONT_EXPORT
ArrayPortalCompositeVector() { }
VTKM_CONT_EXPORT
ArrayPortalCompositeVector(
const PortalTypes portals,
vtkm::Tuple<int, NUM_COMPONENTS> 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<ValueType>(this->SourceComponents),
detail::CompositeVectorPullValueFunctor<ValueType>(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<typename SignatureWithArrays>
class ArrayPortalCompositeVectorCont
{
typedef vtkm::internal::FunctionInterface<SignatureWithArrays>
FunctionInterfaceArrays;
public:
typedef typename FunctionInterfaceArrays::ResultType ValueType;
static const int NUM_COMPONENTS =
vtkm::VectorTraits<ValueType>::NUM_COMPONENTS;
typedef vtkm::Tuple<int, NUM_COMPONENTS> 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<typename SignatureWithArrays>
struct ArrayContainerControlTagCompositeVector { };
/// A convenience class that provides a typedef to the appropriate tag for
/// a counting array container.
template<typename SignatureWithArrays>
struct ArrayHandleCompositeVectorTraits
{
typedef vtkm::cont::internal::ArrayContainerControlTagCompositeVector<
SignatureWithArrays> Tag;
typedef typename vtkm::internal::FunctionInterface<SignatureWithArrays>::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<typename SignatureWithArrays>
class ArrayContainerControl<
typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType,
vtkm::cont::internal::ArrayContainerControlTagCompositeVector<SignatureWithArrays> >
{
typedef vtkm::internal::FunctionInterface<SignatureWithArrays>
FunctionInterfaceWithArrays;
static const int NUM_COMPONENTS = FunctionInterfaceWithArrays::ARITY;
typedef vtkm::Tuple<int, NUM_COMPONENTS> ComponentMapType;
public:
typedef ArrayPortalCompositeVectorCont<SignatureWithArrays> 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<typename SignatureWithArrays, typename DeviceAdapterTag>
class ArrayTransfer<
typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType,
vtkm::cont::internal::ArrayContainerControlTagCompositeVector<SignatureWithArrays>,
DeviceAdapterTag>
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
typedef typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ContainerType
ContainerType;
typedef vtkm::internal::FunctionInterface<SignatureWithArrays>
FunctionWithArrays;
typedef typename FunctionWithArrays::template StaticTransformType<
detail::CompositeVectorArrayToPortalExec<DeviceAdapterTag> >::type
FunctionWithPortals;
typedef typename FunctionWithPortals::Signature SignatureWithPortals;
public:
typedef typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType
ValueType;
// These are not currently fully implemented.
typedef typename ContainerType::PortalType PortalControl;
typedef typename ContainerType::PortalConstType PortalConstControl;
typedef ArrayPortalCompositeVector<SignatureWithPortals> PortalExecution;
typedef ArrayPortalCompositeVector<SignatureWithPortals> 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<typename IteratorTypeControl>
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<DeviceAdapterTag>()),
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<typename Signature>
class ArrayHandleCompositeVector
: public vtkm::cont::ArrayHandle<
typename internal::ArrayHandleCompositeVectorTraits<Signature>::ValueType,
typename internal::ArrayHandleCompositeVectorTraits<Signature>::Tag>
{
typedef typename internal::ArrayHandleCompositeVectorTraits<Signature>::ContainerType
ArrayContainerControlType;
typedef typename internal::ArrayPortalCompositeVectorCont<Signature>::ComponentMapType
ComponentMapType;
public:
typedef vtkm::cont::ArrayHandle<
typename internal::ArrayHandleCompositeVectorTraits<Signature>::ValueType,
typename internal::ArrayHandleCompositeVectorTraits<Signature>::Tag>
Superclass;
typedef typename Superclass::ValueType ValueType;
VTKM_CONT_EXPORT
ArrayHandleCompositeVector() : Superclass() { }
VTKM_CONT_EXPORT
ArrayHandleCompositeVector(
const vtkm::internal::FunctionInterface<Signature> &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<typename ArrayHandleType1>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector(const ArrayHandleType1 &array1,
int sourceComponent1)
: Superclass(ArrayContainerControlType(
vtkm::internal::make_FunctionInterface<ValueType>(array1),
ComponentMapType(sourceComponent1)))
{ }
template<typename ArrayHandleType1,
typename ArrayHandleType2>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector(const ArrayHandleType1 &array1,
int sourceComponent1,
const ArrayHandleType2 &array2,
int sourceComponent2)
: Superclass(ArrayContainerControlType(
vtkm::internal::make_FunctionInterface<ValueType>(
array1, array2),
ComponentMapType(sourceComponent1,
sourceComponent2)))
{ }
template<typename ArrayHandleType1,
typename ArrayHandleType2,
typename ArrayHandleType3>
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<ValueType>(
array1, array2, array3),
ComponentMapType(sourceComponent1,
sourceComponent2,
sourceComponent3)))
{ }
template<typename ArrayHandleType1,
typename ArrayHandleType2,
typename ArrayHandleType3,
typename ArrayHandleType4>
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<ValueType>(
array1, array2, array3, array4),
ComponentMapType(sourceComponent1,
sourceComponent2,
sourceComponent3,
sourceComponent4)))
{ }
};
/// Create a composite vector array from other arrays.
///
template<typename ValueType1, typename Container1>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector<
typename vtkm::VectorTraits<ValueType1>::ComponentType(
vtkm::cont::ArrayHandle<ValueType1,Container1>)>
make_ArrayHandleCompositeVector(
const vtkm::cont::ArrayHandle<ValueType1,Container1> &array1,
int sourceComponent1)
{
return ArrayHandleCompositeVector<
typename vtkm::VectorTraits<ValueType1>::ComponentType(
vtkm::cont::ArrayHandle<ValueType1,Container1>)>(array1,
sourceComponent1);
}
template<typename ValueType1, typename Container1,
typename ValueType2, typename Container2>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,2>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>)>
make_ArrayHandleCompositeVector(
const vtkm::cont::ArrayHandle<ValueType1,Container1> &array1,
int sourceComponent1,
const vtkm::cont::ArrayHandle<ValueType2,Container2> &array2,
int sourceComponent2)
{
return ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,2>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>)>(array1,
sourceComponent1,
array2,
sourceComponent2);
}
template<typename ValueType1, typename Container1,
typename ValueType2, typename Container2,
typename ValueType3, typename Container3>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,3>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>,
vtkm::cont::ArrayHandle<ValueType3,Container3>)>
make_ArrayHandleCompositeVector(
const vtkm::cont::ArrayHandle<ValueType1,Container1> &array1,
int sourceComponent1,
const vtkm::cont::ArrayHandle<ValueType2,Container2> &array2,
int sourceComponent2,
const vtkm::cont::ArrayHandle<ValueType3,Container3> &array3,
int sourceComponent3)
{
return ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,3>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>,
vtkm::cont::ArrayHandle<ValueType3,Container3>)>(array1,
sourceComponent1,
array2,
sourceComponent2,
array3,
sourceComponent3);
}
template<typename ValueType1, typename Container1,
typename ValueType2, typename Container2,
typename ValueType3, typename Container3,
typename ValueType4, typename Container4>
VTKM_CONT_EXPORT
ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,4>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>,
vtkm::cont::ArrayHandle<ValueType3,Container3>,
vtkm::cont::ArrayHandle<ValueType4,Container4>)>
make_ArrayHandleCompositeVector(
const vtkm::cont::ArrayHandle<ValueType1,Container1> &array1,
int sourceComponent1,
const vtkm::cont::ArrayHandle<ValueType2,Container2> &array2,
int sourceComponent2,
const vtkm::cont::ArrayHandle<ValueType3,Container3> &array3,
int sourceComponent3,
const vtkm::cont::ArrayHandle<ValueType4,Container4> &array4,
int sourceComponent4)
{
return ArrayHandleCompositeVector<
vtkm::Tuple<typename vtkm::VectorTraits<ValueType1>::ComponentType,4>(
vtkm::cont::ArrayHandle<ValueType1,Container1>,
vtkm::cont::ArrayHandle<ValueType2,Container2>,
vtkm::cont::ArrayHandle<ValueType3,Container3>,
vtkm::cont::ArrayHandle<ValueType4,Container4>)>(array1,
sourceComponent1,
array2,
sourceComponent2,
array3,
sourceComponent3,
array4,
sourceComponent4);
}
}
} // namespace vtkm::cont
#endif //vtk_m_ArrayHandleCompositeVector_h

@ -25,6 +25,7 @@ set(headers
ArrayContainerControlBasic.h
ArrayContainerControlImplicit.h
ArrayHandle.h
ArrayHandleCompositeVector.h
ArrayHandleCounting.h
ArrayHandleUniformPointCoordinates.h
ArrayPortal.h

@ -29,6 +29,7 @@ set(unit_tests
UnitTestArrayContainerControlBasic.cxx
UnitTestArrayContainerControlImplicit.cxx
UnitTestArrayHandle.cxx
UnitTestArrayHandleCompositeVector.cxx
UnitTestArrayHandleCounting.cxx
UnitTestArrayHandleUniformPointCoordinates.cxx
UnitTestContTesting.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 <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/VectorTraits.h>
#include <vtkm/cont/ArrayContainerControlBasic.h>
#include <vtkm/cont/DeviceAdapterSerial.h>
#include <vtkm/cont/testing/Testing.h>
#include <vector>
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<typename ValueType>
vtkm::cont::ArrayHandle<ValueType, Container>
MakeInputArray(int arrayId)
{
typedef vtkm::VectorTraits<ValueType> 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<ValueType, Container> 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<vtkm::cont::DeviceAdapterTagSerial>::Copy(
bufferHandle, copyHandle);
return copyHandle;
}
template<typename ValueType, typename C>
void CheckArray(const vtkm::cont::ArrayHandle<ValueType,C> &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<ValueType, Container> ArrayHandleType;
ArrayHandleType arrayCopy;
vtkm::cont::DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagSerial>::Copy(
outArray, arrayCopy);
typename ArrayHandleType::PortalConstControl portal =
arrayCopy.GetPortalConstControl();
typedef vtkm::VectorTraits<ValueType> 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<int inComponents>
void TryScalarArray()
{
std::cout << "Creating a scalar array from one of "
<< inComponents << " components." << std::endl;
typedef vtkm::Tuple<vtkm::Scalar,inComponents> InValueType;
typedef vtkm::cont::ArrayHandle<InValueType, Container> InArrayType;
int inArrayId = 0;
InArrayType inArray = MakeInputArray<InValueType>(inArrayId);
typedef vtkm::cont::ArrayHandleCompositeVector<vtkm::Scalar(InArrayType)>
OutArrayType;
for (int inComponentIndex = 0;
inComponentIndex < inComponents;
inComponentIndex++)
{
OutArrayType outArray =
vtkm::cont::make_ArrayHandleCompositeVector(inArray, inComponentIndex);
CheckArray(outArray, &inComponentIndex, &inArrayId);
}
}
template<typename T1, typename T2, typename T3, typename T4>
void TryVector4(vtkm::cont::ArrayHandle<T1,Container> array1,
vtkm::cont::ArrayHandle<T2,Container> array2,
vtkm::cont::ArrayHandle<T3,Container> array3,
vtkm::cont::ArrayHandle<T4,Container> array4)
{
int arrayIds[4] = {0, 1, 2, 3};
int inComponents[4];
for (inComponents[0] = 0;
inComponents[0] < vtkm::VectorTraits<T1>::NUM_COMPONENTS;
inComponents[0]++)
{
for (inComponents[1] = 0;
inComponents[1] < vtkm::VectorTraits<T2>::NUM_COMPONENTS;
inComponents[1]++)
{
for (inComponents[2] = 0;
inComponents[2] < vtkm::VectorTraits<T3>::NUM_COMPONENTS;
inComponents[2]++)
{
for (inComponents[3] = 0;
inComponents[3] < vtkm::VectorTraits<T4>::NUM_COMPONENTS;
inComponents[3]++)
{
CheckArray(
vtkm::cont::make_ArrayHandleCompositeVector(
array1, inComponents[0],
array2, inComponents[1],
array3, inComponents[2],
array4, inComponents[3]),
inComponents,
arrayIds);
}
}
}
}
}
template<typename T1, typename T2, typename T3>
void TryVector3(vtkm::cont::ArrayHandle<T1,Container> array1,
vtkm::cont::ArrayHandle<T2,Container> array2,
vtkm::cont::ArrayHandle<T3,Container> array3)
{
int arrayIds[3] = {0, 1, 2};
int inComponents[3];
for (inComponents[0] = 0;
inComponents[0] < vtkm::VectorTraits<T1>::NUM_COMPONENTS;
inComponents[0]++)
{
for (inComponents[1] = 0;
inComponents[1] < vtkm::VectorTraits<T2>::NUM_COMPONENTS;
inComponents[1]++)
{
for (inComponents[2] = 0;
inComponents[2] < vtkm::VectorTraits<T3>::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<vtkm::Scalar>(3));
std::cout << " Fourth component from Vector4." << std::endl;
TryVector4(array1, array2, array3, MakeInputArray<vtkm::Vector4>(3));
}
template<typename T1, typename T2>
void TryVector2(vtkm::cont::ArrayHandle<T1,Container> array1,
vtkm::cont::ArrayHandle<T2,Container> array2)
{
int arrayIds[2] = {0, 1};
int inComponents[2];
for (inComponents[0] = 0;
inComponents[0] < vtkm::VectorTraits<T1>::NUM_COMPONENTS;
inComponents[0]++)
{
for (inComponents[1] = 0;
inComponents[1] < vtkm::VectorTraits<T2>::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<vtkm::Scalar>(2));
std::cout << " Third component from Vector2." << std::endl;
TryVector3(array1, array2, MakeInputArray<vtkm::Vector2>(2));
}
template<typename T1>
void TryVector1(vtkm::cont::ArrayHandle<T1,Container> array1)
{
int arrayIds[1] = {0};
int inComponents[1];
for (inComponents[0] = 0;
inComponents[0] < vtkm::VectorTraits<T1>::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<vtkm::Scalar>(1));
std::cout << " Second component from Vector4." << std::endl;
TryVector2(array1, MakeInputArray<vtkm::Vector4>(1));
}
void TryVector()
{
std::cout << "Trying many permutations of composite vectors." << std::endl;
std::cout << " First component from Scalar." << std::endl;
TryVector1(MakeInputArray<vtkm::Scalar>(0));
std::cout << " First component from Vector3." << std::endl;
TryVector1(MakeInputArray<vtkm::Vector3>(0));
}
void TestBadArrayLengths() {
std::cout << "Checking behavior when size of input arrays do not agree."
<< std::endl;
typedef vtkm::cont::ArrayHandle<vtkm::Id, Container> InArrayType;
InArrayType longInArray = MakeInputArray<vtkm::Id>(0);
InArrayType shortInArray = MakeInputArray<vtkm::Id>(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);
}