Commit 42aba977 authored by Kenneth Moreland's avatar Kenneth Moreland
Browse files

Add in-place (in-out) arrays to worklets.

Previously, all arrays passed to worklets were designated as either
input or output. No in-place operation was permitted. This change adds
the FieldInOut tag for ControlSignature in both WorkletMapField and
WorkletMapTopology that allows you to read and write from the same
array.
parent 8a0f5186
......@@ -24,6 +24,7 @@ set(headers
ControlSignatureTagBase.h
Transport.h
TransportTagArrayIn.h
TransportTagArrayInOut.h
TransportTagArrayOut.h
TransportTagExecObject.h
TransportTagTopologyIn.h
......
......@@ -48,6 +48,11 @@ struct Transport<vtkm::cont::arg::TransportTagArrayIn, ContObjectType, Device>
VTKM_CONT_EXPORT
ExecObjectType operator()(const ContObjectType &object, vtkm::Id) const
{
// TODO: Throw an exception if object.GetNumberOfValues() does not equal
// the size passed into this operator. Currently, the size passed into
// this method is sometimes wrong (for example with point fields when
// mapping on cells).
return object.PrepareForInput(Device());
}
};
......
//============================================================================
// 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 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 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_cont_arg_TransportTagArrayInOut_h
#define vtk_m_cont_arg_TransportTagArrayInOut_h
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/arg/Transport.h>
namespace vtkm {
namespace cont {
namespace arg {
/// \brief \c Transport tag for in-place arrays.
///
/// \c TransportTagArrayInOut is a tag used with the \c Transport class to
/// transport \c ArrayHandle objects for data that is both input and output
/// (that is, in place modification of array data).
///
struct TransportTagArrayInOut { };
template<typename ContObjectType, typename Device>
struct Transport<vtkm::cont::arg::TransportTagArrayInOut, ContObjectType, Device>
{
// If you get a compile error here, it means you tried to use an object that
// is not an array handle as an argument that is expected to be one.
VTKM_IS_ARRAY_HANDLE(ContObjectType);
typedef typename ContObjectType::template ExecutionTypes<Device>::Portal
ExecObjectType;
VTKM_CONT_EXPORT
ExecObjectType operator()(ContObjectType object, vtkm::Id size) const
{
if (object.GetNumberOfValues() != size)
{
throw vtkm::cont::ErrorControlBadValue(
"Input array to worklet invocation the wrong size.");
}
return object.PrepareForInPlace(Device());
}
};
}
}
} // namespace vtkm::cont::arg
#endif //vtk_m_cont_arg_TransportTagArrayInOut_h
......@@ -21,6 +21,7 @@
set(unit_tests
UnitTestControlSignatureTag.cxx
UnitTestTransportArrayIn.cxx
UnitTestTransportArrayInOut.cxx
UnitTestTransportArrayOut.cxx
UnitTestTransportExecObject.cxx
UnitTestTypeCheckArray.cxx
......
//============================================================================
// 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 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 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.
//============================================================================
#include <vtkm/cont/arg/TransportTagArrayInOut.h>
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/testing/Testing.h>
namespace {
static const vtkm::Id ARRAY_SIZE = 10;
template<typename PortalType>
struct TestKernel : public vtkm::exec::FunctorBase
{
PortalType Portal;
VTKM_EXEC_EXPORT
void operator()(vtkm::Id index) const
{
typedef typename PortalType::ValueType ValueType;
ValueType inValue = this->Portal.Get(index);
this->Portal.Set(index, inValue + inValue);
}
};
template<typename Device>
struct TryArrayInOutType
{
template<typename T>
void operator()(T) const
{
T array[ARRAY_SIZE];
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
array[index] = TestValue(index, T());
}
typedef vtkm::cont::ArrayHandle<T> ArrayHandleType;
ArrayHandleType handle = vtkm::cont::make_ArrayHandle(array, ARRAY_SIZE);
typedef typename ArrayHandleType::
template ExecutionTypes<Device>::Portal PortalType;
vtkm::cont::arg::Transport<
vtkm::cont::arg::TransportTagArrayInOut, ArrayHandleType, Device>
transport;
TestKernel<PortalType> kernel;
kernel.Portal = transport(handle, ARRAY_SIZE);
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(kernel, ARRAY_SIZE);
typename ArrayHandleType::PortalConstControl portal =
handle.GetPortalConstControl();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE,
"Portal has wrong number of values.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
T expectedValue = TestValue(index, T()) + TestValue(index, T());
T retrievedValue = portal.Get(index);
VTKM_TEST_ASSERT(test_equal(expectedValue, retrievedValue),
"Functor did not modify in place.");
}
}
};
template<typename Device>
void TryArrayInOutTransport(Device)
{
vtkm::testing::Testing::TryTypes(TryArrayInOutType<Device>(),
vtkm::TypeListTagCommon());
}
void TestArrayInOutTransport()
{
TryArrayInOutTransport(VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
}
} // anonymous namespace
int UnitTestTransportArrayInOut(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestArrayInOutTransport);
}
......@@ -25,6 +25,7 @@ set(headers
ExecutionSignatureTagBase.h
Fetch.h
FetchTagArrayDirectIn.h
FetchTagArrayDirectInOut.h
FetchTagArrayDirectOut.h
FetchTagArrayTopologyMapIn.h
FetchTagExecObject.h
......
//============================================================================
// 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 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 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_exec_arg_FetchTagArrayDirectInOut_h
#define vtk_m_exec_arg_FetchTagArrayDirectInOut_h
#include <vtkm/exec/arg/AspectTagDefault.h>
#include <vtkm/exec/arg/Fetch.h>
namespace vtkm {
namespace exec {
namespace arg {
/// \brief \c Fetch tag for in-place modifying array values with direct indexing.
///
/// \c FetchTagArrayDirectInOut is a tag used with the \c Fetch class to do
/// in-place modification of values in an array portal. The fetch uses direct
/// indexing, so the thread index given to \c Store is used as the index into
/// the array.
///
struct FetchTagArrayDirectInOut { };
template<typename Invocation, vtkm::IdComponent ParameterIndex>
struct Fetch<
vtkm::exec::arg::FetchTagArrayDirectInOut,
vtkm::exec::arg::AspectTagDefault,
Invocation,
ParameterIndex>
{
typedef typename Invocation::ParameterInterface::
template ParameterType<ParameterIndex>::type ExecObjectType;
typedef typename ExecObjectType::ValueType ValueType;
VTKM_EXEC_EXPORT
ValueType Load(vtkm::Id index, const Invocation &invocation) const
{
return invocation.Parameters.template GetParameter<ParameterIndex>().
Get(index);
}
VTKM_EXEC_EXPORT
void Store(vtkm::Id index,
const Invocation &invocation,
const ValueType &value) const
{
invocation.Parameters.template GetParameter<ParameterIndex>().
Set(index, value);
}
};
}
}
} // namespace vtkm::exec::arg
#endif //vtk_m_exec_arg_FetchTagArrayDirectInOut_h
......@@ -21,6 +21,7 @@
set(unit_tests
UnitTestExecutionSignatureTag.cxx
UnitTestFetchArrayDirectIn.cxx
UnitTestFetchArrayDirectInOut.cxx
UnitTestFetchArrayDirectOut.cxx
UnitTestFetchExecObject.cxx
UnitTestFetchWorkIndex.cxx
......
//============================================================================
// 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 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 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.
//============================================================================
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
#include <vtkm/internal/FunctionInterface.h>
#include <vtkm/internal/Invocation.h>
#include <vtkm/testing/Testing.h>
namespace {
static const vtkm::Id ARRAY_SIZE = 10;
static vtkm::Id g_NumSets;
template<typename T>
struct TestPortal
{
typedef T ValueType;
VTKM_EXEC_CONT_EXPORT
vtkm::Id GetNumberOfValues() const { return ARRAY_SIZE; }
VTKM_EXEC_CONT_EXPORT
ValueType Get(vtkm::Id index) const {
VTKM_TEST_ASSERT(index >= 0, "Bad portal index.");
VTKM_TEST_ASSERT(index < this->GetNumberOfValues(), "Bad portal index.");
return TestValue(index, ValueType());
}
VTKM_EXEC_CONT_EXPORT
void Set(vtkm::Id index, const ValueType &value) const {
VTKM_TEST_ASSERT(index >= 0, "Bad portal index.");
VTKM_TEST_ASSERT(index < this->GetNumberOfValues(), "Bad portal index.");
VTKM_TEST_ASSERT(
test_equal(value, ValueType(2)*TestValue(index, ValueType())),
"Tried to set invalid value.");
g_NumSets++;
}
};
struct NullParam { };
template<vtkm::IdComponent ParamIndex, typename T>
struct FetchArrayDirectInTests
{
template<typename Invocation>
void TryInvocation(const Invocation &invocation) const
{
typedef vtkm::exec::arg::Fetch<
vtkm::exec::arg::FetchTagArrayDirectInOut,
vtkm::exec::arg::AspectTagDefault,
Invocation,
ParamIndex> FetchType;
FetchType fetch;
g_NumSets = 0;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
T value = fetch.Load(index, invocation);
VTKM_TEST_ASSERT(test_equal(value, TestValue(index, T())),
"Got invalid value from Load.");
value = T(T(2)*value);
fetch.Store(index, invocation, value);
}
VTKM_TEST_ASSERT(g_NumSets == ARRAY_SIZE,
"Array portal's set not called correct number of times."
"Store method must be wrong.");
}
void operator()() const
{
std::cout << "Trying ArrayDirectInOut fetch on parameter " << ParamIndex
<< " with type " << vtkm::testing::TypeName<T>::Name()
<< std::endl;
typedef vtkm::internal::FunctionInterface<
void(NullParam,NullParam,NullParam,NullParam,NullParam)>
BaseFunctionInterface;
this->TryInvocation(vtkm::internal::make_Invocation<1>(
BaseFunctionInterface().Replace<ParamIndex>(
TestPortal<T>()),
NullParam(),
NullParam()));
}
};
struct TryType
{
template<typename T>
void operator()(T) const
{
FetchArrayDirectInTests<1,T>()();
FetchArrayDirectInTests<2,T>()();
FetchArrayDirectInTests<3,T>()();
FetchArrayDirectInTests<4,T>()();
FetchArrayDirectInTests<5,T>()();
}
};
void TestExecObjectFetch()
{
vtkm::testing::Testing::TryTypes(TryType(), vtkm::TypeListTagCommon());
}
} // anonymous namespace
int UnitTestFetchArrayDirectInOut(int, char *[])
{
return vtkm::testing::Testing::Run(TestExecObjectFetch);
}
......@@ -26,10 +26,12 @@
#include <vtkm/cont/arg/ControlSignatureTagBase.h>
#include <vtkm/cont/arg/TransportTagArrayIn.h>
#include <vtkm/cont/arg/TransportTagArrayInOut.h>
#include <vtkm/cont/arg/TransportTagArrayOut.h>
#include <vtkm/cont/arg/TypeCheckTagArray.h>
#include <vtkm/exec/arg/FetchTagArrayDirectIn.h>
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
namespace vtkm {
......@@ -65,6 +67,18 @@ public:
typedef vtkm::cont::arg::TransportTagArrayOut TransportTag;
typedef vtkm::exec::arg::FetchTagArrayDirectOut FetchTag;
};
/// \brief A control signature tag for input-output (in-place) fields.
///
/// This tag takes a template argument that is a type list tag that limits
/// the possible value types in the array.
///
template<typename TypeList = AllTypes>
struct FieldInOut : vtkm::cont::arg::ControlSignatureTagBase {
typedef vtkm::cont::arg::TypeCheckTagArray<TypeList> TypeCheckTag;
typedef vtkm::cont::arg::TransportTagArrayInOut TransportTag;
typedef vtkm::exec::arg::FetchTagArrayDirectInOut FetchTag;
};
};
}
......
......@@ -26,6 +26,7 @@
#include <vtkm/cont/arg/ControlSignatureTagBase.h>
#include <vtkm/cont/arg/TransportTagArrayIn.h>
#include <vtkm/cont/arg/TransportTagArrayInOut.h>
#include <vtkm/cont/arg/TransportTagArrayOut.h>
#include <vtkm/cont/arg/TransportTagTopologyIn.h>
#include <vtkm/cont/arg/TypeCheckTagArray.h>
......@@ -33,6 +34,7 @@
#include <vtkm/exec/arg/CellShape.h>
#include <vtkm/exec/arg/FetchTagArrayDirectIn.h>
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
#include <vtkm/exec/arg/FetchTagTopologyIn.h>
#include <vtkm/exec/arg/FetchTagArrayTopologyMapIn.h>
......@@ -104,6 +106,18 @@ public:
typedef vtkm::exec::arg::FetchTagArrayDirectOut FetchTag;
};
/// \brief A control signature tag for input-output (in-place) fields.
///
/// This tag takes a template argument that is a type list tag that limits
/// the possible value types in the array.
///
template<typename TypeList = AllTypes>
struct FieldInOut : vtkm::cont::arg::ControlSignatureTagBase {
typedef vtkm::cont::arg::TypeCheckTagArray<TypeList> TypeCheckTag;
typedef vtkm::cont::arg::TransportTagArrayInOut TransportTag;
typedef vtkm::exec::arg::FetchTagArrayDirectInOut FetchTag;
};
/// \brief An execution signature tag for getting the cell shape.
///
struct CellShape : vtkm::exec::arg::CellShape { };
......
......@@ -28,23 +28,28 @@
class TestMapFieldWorklet : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<>, FieldOut<>);
typedef void ExecutionSignature(_1, _2, WorkIndex);
typedef void ControlSignature(FieldIn<>, FieldOut<>, FieldInOut<>);
typedef void ExecutionSignature(_1, _2, _3, WorkIndex);
template<typename T>
VTKM_EXEC_EXPORT
void operator()(const T &in, T &out, vtkm::Id workIndex) const
void operator()(const T &in, T &out, T &inout, vtkm::Id workIndex) const
{
if (!test_equal(in, TestValue(workIndex, T()) + T(100)))
{
this->RaiseError("Got wrong input value.");
}
out = in - T(100);
if (!test_equal(inout, TestValue(workIndex, T()) + T(100)))
{
this->RaiseError("Got wrong in-out value.");
}
inout = inout - T(100);
}
template<typename T1, typename T2>
template<typename T1, typename T2, typename T3>
VTKM_EXEC_EXPORT
void operator()(const T1 &, const T2 &, vtkm::Id) const
void operator()(const T1 &, const T2 &, const T3 &, vtkm::Id) const
{
this->RaiseError("Cannot call this worklet with different types.");
}
......@@ -53,18 +58,27 @@ public:
class TestMapFieldWorkletLimitedTypes : public vtkm::worklet::WorkletMapField
{
public:
typedef void ControlSignature(FieldIn<ScalarAll>, FieldOut<ScalarAll>);
typedef _2 ExecutionSignature(_1, WorkIndex);
typedef void ControlSignature(FieldIn<ScalarAll>,
FieldOut<ScalarAll>,
FieldInOut<ScalarAll>);
typedef _2 ExecutionSignature(_1, _3, WorkIndex);
template<typename T>
template<typename T1, typename T3>
VTKM_EXEC_EXPORT
T operator()(const T &in, vtkm::Id workIndex) const
T1 operator()(const T1 &in, T3 &inout, vtkm::Id workIndex) const
{
if (!test_equal(in, TestValue(workIndex, T()) + T(100)))
if (!test_equal(in, TestValue(workIndex, T1()) + T1(100)))
{
this->RaiseError("Got wrong input value.");
}
return in - T(100);
if (!test_equal(inout, TestValue(workIndex, T3()) + T3(100)))
{
this->RaiseError("Got wrong in-out value.");
}
inout = inout - T3(100);
return in - T1(100);
}
};
......@@ -90,21 +104,30 @@ struct DoTestWorklet
vtkm::cont::ArrayHandle<T> inputHandle =
vtkm::cont::make_ArrayHandle(inputArray, ARRAY_SIZE);
vtkm::cont::ArrayHandle<T> outputHandle;
vtkm::cont::ArrayHandle<T> inoutHandle;
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(inputHandle, inoutHandle);
std::cout << "Create and run dispatcher." << std::endl;
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
dispatcher.Invoke(inputHandle, outputHandle);
dispatcher.Invoke(inputHandle, outputHandle, inoutHandle);
std::cout << "Check result." << std::endl;
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
std::cout << "Repeat with dynamic arrays." << std::endl;
// Clear out output array.
outputHandle = vtkm::cont::ArrayHandle<T>();
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(inputHandle, inoutHandle);
vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
dispatcher.Invoke(inputDynamic, outputDynamic);
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
dispatcher.Invoke(inputDynamic, outputDynamic, inoutDynamic);
CheckPortal(outputHandle.GetPortalConstControl());
CheckPortal(inoutHandle.GetPortalConstControl());
}
};
......