vtk-m2/vtkm/cont/testing/TestingDeviceAdapter.h

2205 lines
79 KiB
C
Raw Normal View History

//============================================================================
// 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_cont_testing_TestingDeviceAdapter_h
#define vtk_m_cont_testing_TestingDeviceAdapter_h
#include <vtkm/TypeTraits.h>
#include <vtkm/BinaryPredicates.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/cont/ArrayHandle.h>
2015-06-10 20:37:52 +00:00
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
2015-06-10 20:37:52 +00:00
#include <vtkm/cont/ArrayHandleZip.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/StorageBasic.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/internal/DeviceAdapterError.h>
#include <vtkm/cont/testing/Testing.h>
2016-02-10 15:51:31 +00:00
#include <vtkm/exec/AtomicArray.h>
#include <algorithm>
#include <cmath>
#include <utility>
#include <vector>
#include <vtkm/internal/Windows.h>
namespace vtkm {
namespace cont {
namespace testing {
#define ERROR_MESSAGE "Got an error."
#define ARRAY_SIZE 100000
#define OFFSET 1000
#define DIM_SIZE 128
/// This class has a single static member, Run, that tests the templated
/// DeviceAdapter for conformance.
///
template<class DeviceAdapterTag>
struct TestingDeviceAdapter
{
private:
typedef vtkm::cont::StorageTagBasic StorageTag;
typedef vtkm::cont::ArrayHandle<vtkm::Id, StorageTag>
IdArrayHandle;
typedef vtkm::cont::ArrayHandle<vtkm::FloatDefault,StorageTag>
ScalarArrayHandle;
typedef vtkm::cont::internal::ArrayManagerExecution<
vtkm::Id, StorageTag, DeviceAdapterTag>
IdArrayManagerExecution;
typedef vtkm::cont::internal::Storage<vtkm::Id, StorageTag> IdStorage;
typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
::Portal IdPortalType;
typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
::PortalConst IdPortalConstType;
typedef vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag>
Algorithm;
public:
// Cuda kernels have to be public (in Cuda 4.0).
struct CopyArrayKernel
{
VTKM_CONT
CopyArrayKernel(const IdPortalConstType &input,
const IdPortalType &output)
: InputArray(input), OutputArray(output) { }
VTKM_EXEC void operator()(
vtkm::Id index,
const vtkm::exec::internal::ErrorMessageBuffer &) const
{
this->OutputArray.Set(index, this->InputArray.Get(index));
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalConstType InputArray;
IdPortalType OutputArray;
};
struct ClearArrayKernel
{
VTKM_CONT
ClearArrayKernel(const IdPortalType &array) : Array(array), Dims() { }
VTKM_CONT
ClearArrayKernel(const IdPortalType &array,
const vtkm::Id3& dims) : Array(array), Dims(dims) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, OFFSET);
}
VTKM_EXEC void operator()(vtkm::Id3 index) const
{
//convert from id3 to id
vtkm::Id flatIndex =
index[0]+ this->Dims[0]*(index[1]+ this->Dims[1]*index[2]);
this->operator()(flatIndex);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
vtkm::Id3 Dims;
};
struct ClearArrayMapKernel //: public vtkm::exec::WorkletMapField
{
// typedef void ControlSignature(Field(Out));
// typedef void ExecutionSignature(_1);
template<typename T>
VTKM_EXEC void operator()(T& value) const
{
value = OFFSET;
}
};
struct AddArrayKernel
{
VTKM_CONT
AddArrayKernel(const IdPortalType &array) : Array(array), Dims() { }
VTKM_CONT
AddArrayKernel(const IdPortalType &array,
const vtkm::Id3& dims) : Array(array), Dims(dims) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, this->Array.Get(index) + index);
}
VTKM_EXEC void operator()(vtkm::Id3 index) const
{
//convert from id3 to id
vtkm::Id flatIndex =
index[0]+ this->Dims[0]*(index[1]+ this->Dims[1]*index[2]);
this->operator()(flatIndex);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
vtkm::Id3 Dims;
};
struct OneErrorKernel
{
VTKM_EXEC void operator()(vtkm::Id index) const
{
if (index == ARRAY_SIZE/2)
{
this->ErrorMessage.RaiseError(ERROR_MESSAGE);
}
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
{
this->ErrorMessage = errorMessage;
}
vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
};
struct AllErrorKernel
{
VTKM_EXEC void operator()(vtkm::Id vtkmNotUsed(index)) const
{
this->ErrorMessage.RaiseError(ERROR_MESSAGE);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
{
this->ErrorMessage = errorMessage;
}
vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
};
struct OffsetPlusIndexKernel
{
VTKM_CONT
OffsetPlusIndexKernel(const IdPortalType &array) : Array(array) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, OFFSET + index);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
};
struct MarkOddNumbersKernel
{
VTKM_CONT
MarkOddNumbersKernel(const IdPortalType &array) : Array(array) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, index%2);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
};
struct FuseAll
{
template<typename T>
VTKM_EXEC bool operator()(const T&, const T&) const
{
//binary predicates for unique return true if they are the same
return true;
}
};
2016-02-10 15:51:31 +00:00
template<typename T>
struct AtomicKernel
2016-02-10 15:51:31 +00:00
{
VTKM_CONT
2016-02-10 15:51:31 +00:00
AtomicKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
: AArray(array)
{ }
VTKM_EXEC void operator()(vtkm::Id index) const
2016-02-10 15:51:31 +00:00
{
T value = (T) index;
this->AArray.Add(0, value);
2016-02-10 15:51:31 +00:00
}
VTKM_CONT void SetErrorMessageBuffer(
2016-02-10 15:51:31 +00:00
const vtkm::exec::internal::ErrorMessageBuffer &) { }
vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
};
template<typename T>
struct AtomicCASKernel
{
VTKM_CONT
AtomicCASKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
: AArray(array)
{ }
VTKM_EXEC void operator()(vtkm::Id index) const
{
T value = (T) index;
//Get the old value from the array with a no-op
T oldValue = this->AArray.Add(0,T(0));
//This creates an atomic add using the CAS operatoin
T assumed = T(0);
do
{
assumed = oldValue;
oldValue = this->AArray.CompareAndSwap(0, (assumed + value) , assumed);
} while (assumed != oldValue);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
};
private:
static VTKM_CONT void TestDeviceAdapterTag()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing device adapter tag" << std::endl;
typedef vtkm::cont::DeviceAdapterTraits<DeviceAdapterTag> Traits;
typedef vtkm::cont::DeviceAdapterTraits<
vtkm::cont::DeviceAdapterTagError> ErrorTraits;
VTKM_TEST_ASSERT(Traits::GetId() == Traits::GetId(),
"Device adapter Id does not equal itself.");
VTKM_TEST_ASSERT(Traits::GetId() != ErrorTraits::GetId(),
"Device adapter Id not distinguishable from others.");
VTKM_TEST_ASSERT(Traits::GetName() == Traits::GetName(),
"Device adapter Name does not equal itself.");
VTKM_TEST_ASSERT(Traits::GetName() != ErrorTraits::GetName(),
"Device adapter Name not distinguishable from others.");
}
// Note: this test does not actually test to make sure the data is available
// in the execution environment. It tests to make sure data gets to the array
// and back, but it is possible that the data is not available in the
// execution environment.
static VTKM_CONT void TestArrayManagerExecution()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayManagerExecution" << std::endl;
typedef vtkm::cont::internal::ArrayManagerExecution<
vtkm::Id,StorageTagBasic,DeviceAdapterTag>
ArrayManagerExecution;
typedef vtkm::cont::internal::Storage<vtkm::Id,StorageTagBasic> StorageType;
// Create original input array.
StorageType storage;
storage.Allocate(ARRAY_SIZE*2);
StorageType::PortalType portal = storage.GetPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE*2,
"Storage portal has unexpected size.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
portal.Set(index, TestValue(index, vtkm::Id()));
}
ArrayManagerExecution manager(&storage);
// Do an operation just so we know the values are placed in the execution
// environment and they change. We are only calling on half the array
// because we are about to shrink.
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(true)),
ARRAY_SIZE);
// Change size.
manager.Shrink(ARRAY_SIZE);
VTKM_TEST_ASSERT(manager.GetNumberOfValues() == ARRAY_SIZE,
"Shrink did not set size of array manager correctly.");
// Get the array back and check its values. We have to get it back into
// the same storage since some ArrayManagerExecution classes will expect
// that.
manager.RetrieveOutputData(&storage);
VTKM_TEST_ASSERT(storage.GetNumberOfValues() == ARRAY_SIZE,
"Storage has wrong number of values after execution "
"array shrink.");
// Check array.
StorageType::PortalConstType checkPortal = storage.GetPortalConst();
VTKM_TEST_ASSERT(checkPortal.GetNumberOfValues() == ARRAY_SIZE,
"Storage portal wrong size.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
VTKM_TEST_ASSERT(
checkPortal.Get(index) == TestValue(index, vtkm::Id()) + index,
"Did not get correct values from array.");
}
}
static VTKM_CONT void TestOutOfMemory()
{
// Only test out of memory with 64 bit ids. If there are 32 bit ids on
// a 64 bit OS (common), it is simply too hard to get a reliable allocation
// that is too much memory.
#ifdef VTKM_USE_64BIT_IDS
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Out of Memory" << std::endl;
try
{
std::cout << "Do array allocation that should fail." << std::endl;
vtkm::cont::internal::Storage<
vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic> supportArray;
vtkm::cont::internal::ArrayManagerExecution<
vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic, DeviceAdapterTag>
bigManager(&supportArray);
const vtkm::Id bigSize = 0x7FFFFFFFFFFFFFFFLL;
bigManager.PrepareForOutput(bigSize);
// It does not seem reasonable to get here. The previous call should fail.
VTKM_TEST_FAIL("A ridiculously sized allocation succeeded. Either there "
"was a failure that was not reported but should have been "
"or the width of vtkm::Id is not large enough to express all "
"array sizes.");
}
2017-02-23 15:13:30 +00:00
catch (vtkm::cont::ErrorBadAllocation &error)
{
std::cout << "Got the expected error: " << error.GetMessage() << std::endl;
}
#else
std::cout << "--------- Skipping out of memory test" << std::endl;
#endif
}
VTKM_CONT
static void TestTimer()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Timer" << std::endl;
vtkm::cont::Timer<DeviceAdapterTag> timer;
std::cout << "Timer started. Sleeping..." << std::endl;
#ifndef _WIN32
sleep(1);
#else
Sleep(1000);
#endif
std::cout << "Woke up. Check time." << std::endl;
vtkm::Float64 elapsedTime = timer.GetElapsedTime();
std::cout << "Elapsed time: " << elapsedTime << std::endl;
VTKM_TEST_ASSERT(elapsedTime > 0.999,
"Timer did not capture full second wait.");
VTKM_TEST_ASSERT(elapsedTime < 2.0,
"Timer counted too far or system really busy.");
}
VTKM_CONT
static void TestRuntime()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing RuntimeDeviceInformation" << std::endl;
vtkm::cont::RuntimeDeviceInformation<DeviceAdapterTag> runtime;
const bool valid_runtime = runtime.Exists();
VTKM_TEST_ASSERT(valid_runtime, "runtime detection failed for device");
}
static VTKM_CONT void TestAlgorithmSchedule()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing single value Scheduling with vtkm::Id" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(1)), 1);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)), 1);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < 1; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for single value scheduled kernel.");
}
} //release memory
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with vtkm::Id" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(ARRAY_SIZE)),
ARRAY_SIZE);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
ARRAY_SIZE);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled kernels.");
}
} //release memory
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with a vary large Id value" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
//size is selected to be larger than the CUDA backend can launch in a
//single invocation when compiled for SM_2 support
const vtkm::Id size = 8400000;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(size)),
size);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
size);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < size; index+=100)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled kernels.");
}
} //release memory
//verify that the schedule call works with id3
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with vtkm::Id3" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
vtkm::Id3 maxRange(DIM_SIZE);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(
ClearArrayKernel(manager.PrepareForOutput(
DIM_SIZE * DIM_SIZE * DIM_SIZE), maxRange),
maxRange);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false), maxRange),
maxRange);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
const vtkm::Id maxId = DIM_SIZE * DIM_SIZE * DIM_SIZE;
for (vtkm::Id index = 0; index < maxId; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled vtkm::Id3 kernels.");
}
} //release memory
}
static VTKM_CONT void TestCopyIf()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing CopyIf" << std::endl;
IdArrayHandle array;
IdArrayHandle stencil;
IdArrayHandle result;
std::cout << " Standard call" << std::endl;
//construct the index array
Algorithm::Schedule(
OffsetPlusIndexKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
MarkOddNumbersKernel(stencil.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::CopyIf(array,stencil,result);
VTKM_TEST_ASSERT(result.GetNumberOfValues() == array.GetNumberOfValues()/2,
"result of CopyIf has an incorrect size");
for (vtkm::Id index = 0; index < result.GetNumberOfValues(); index++)
{
const vtkm::Id value = result.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(value == (OFFSET + (index*2)+1),
"Incorrect value in CopyIf result.");
}
std::cout << " CopyIf on zero size arrays." << std::endl;
array.Shrink(0);
stencil.Shrink(0);
Algorithm::CopyIf(array, stencil, result);
VTKM_TEST_ASSERT(result.GetNumberOfValues() == 0,
"result of CopyIf has an incorrect size");
}
static VTKM_CONT void TestOrderedUniqueValues()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(&(*testData.begin()), ARRAY_SIZE);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
IdArrayHandle handle1;
//verify lower and upper bounds work
Algorithm::LowerBounds(temp,input,handle);
Algorithm::UpperBounds(temp,input,handle1);
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
vtkm::Id value1 = handle1.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i % 50, "Got bad value (LowerBounds)");
VTKM_TEST_ASSERT(value1 >= i % 50, "Got bad value (UpperBounds)");
}
std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds with random values"
<< std::endl;
//now test it works when the id are not incrementing
const vtkm::Id RANDOMDATA_SIZE = 6;
vtkm::Id randomData[RANDOMDATA_SIZE];
randomData[0]=500; // 2 (lower), 3 (upper)
randomData[1]=955; // 3 (lower), 4 (upper)
randomData[2]=955; // 3 (lower), 4 (upper)
randomData[3]=120; // 0 (lower), 1 (upper)
randomData[4]=320; // 1 (lower), 2 (upper)
randomData[5]=955; // 3 (lower), 4 (upper)
//change the control structure under the handle
input = vtkm::cont::make_ArrayHandle(randomData, RANDOMDATA_SIZE);
Algorithm::Copy(input,handle);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"Handle incorrect size after setting new control data");
Algorithm::Copy(input,handle1);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"Handle incorrect size after setting new control data");
Algorithm::Copy(handle,temp);
VTKM_TEST_ASSERT(temp.GetNumberOfValues() == RANDOMDATA_SIZE,
"Copy failed");
Algorithm::Sort(temp);
Algorithm::Unique(temp);
Algorithm::LowerBounds(temp,handle);
Algorithm::UpperBounds(temp,handle1);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"LowerBounds returned incorrect size");
std::copy(
vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalConstControl()),
randomData);
VTKM_TEST_ASSERT(randomData[0] == 2, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[1] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[2] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[3] == 0, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[4] == 1, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[5] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(handle1.GetNumberOfValues() == RANDOMDATA_SIZE,
"UppererBounds returned incorrect size");
std::copy(
vtkm::cont::ArrayPortalToIteratorBegin(handle1.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(handle1.GetPortalConstControl()),
randomData);
VTKM_TEST_ASSERT(randomData[0] == 3, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[1] == 4, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[2] == 4, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[3] == 1, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[4] == 2, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[5] == 4, "Got bad value - UpperBound");
}
static VTKM_CONT void TestSort()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData);
IdArrayHandle sorted;
Algorithm::Copy(unsorted, sorted);
//Validate the standard inplace sort is correct
Algorithm::Sort(sorted);
for (vtkm::Id i = 0; i < ARRAY_SIZE-1; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = sorted.GetPortalConstControl().Get(i+1);
VTKM_TEST_ASSERT(sorted1 <= sorted2, "Values not properly sorted.");
}
//Try zero sized array
sorted.Shrink(0);
Algorithm::Sort(sorted);
}
static VTKM_CONT void TestSortWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
//sort the users memory in-place
IdArrayHandle sorted = vtkm::cont::make_ArrayHandle(testData);
Algorithm::Sort(sorted);
//copy the sorted array into our own memory, if use the same user ptr
//we would also sort the 'sorted' handle
IdArrayHandle comp_sorted;
Algorithm::Copy(sorted, comp_sorted);
Algorithm::Sort(comp_sorted,vtkm::SortGreater());
//Validate that sorted and comp_sorted are sorted in the opposite directions
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(ARRAY_SIZE - (i + 1));
VTKM_TEST_ASSERT(sorted1 == sorted2,
"Got bad sort values when using SortGreater");
}
//validate that sorted and comp_sorted are now equal
Algorithm::Sort(comp_sorted,vtkm::SortLess());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(sorted1 == sorted2,
"Got bad sort values when using SortLess");
}
}
static VTKM_CONT void TestSortWithFancyArrays()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort of a ArrayHandleZip" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData);
IdArrayHandle sorted;
Algorithm::Copy(unsorted, sorted);
//verify that we can use ArrayHandleZip inplace
vtkm::cont::ArrayHandleZip< IdArrayHandle, IdArrayHandle> zipped(unsorted, sorted);
//verify we can use sort with zip handle
Algorithm::Sort(zipped, vtkm::SortGreater());
Algorithm::Sort(zipped);
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Pair<vtkm::Id,vtkm::Id> kv_sorted = zipped.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( i / (ARRAY_SIZE/50)) ) == kv_sorted.first,
"ArrayZipHandle improperly sorted");
}
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort of a ArrayHandlePermutation" << std::endl;
//verify that we can use ArrayHandlePermutation inplace
vtkm::cont::ArrayHandleIndex index(ARRAY_SIZE);
vtkm::cont::ArrayHandlePermutation< vtkm::cont::ArrayHandleIndex,
IdArrayHandle> perm(index, sorted);
//verify we can use a custom operator sort with permutation handle
Algorithm::Sort(perm, vtkm::SortGreater());
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( (ARRAY_SIZE-(i+1)) / (ARRAY_SIZE/50)) ) == sorted_value,
"ArrayZipPermutation improperly sorted");
}
//verify we can use the default sort with permutation handle
Algorithm::Sort(perm);
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( i / (ARRAY_SIZE/50)) ) == sorted_value,
"ArrayZipPermutation improperly sorted");
}
}
static VTKM_CONT void TestSortByKey()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort by keys" << std::endl;
typedef vtkm::Vec<FloatDefault,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault,3>,StorageTag>
Vec3ArrayHandle;
std::vector<vtkm::Id> testKeys(ARRAY_SIZE);
std::vector<Vec3> testValues(testKeys.size());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
std::size_t index = static_cast<size_t>(i);
testKeys[index] = ARRAY_SIZE - i;
testValues[index] = TestValue(i, Vec3());
}
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(testKeys);
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Algorithm::SortByKey(keys,values);
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from 1 to ARRAY_SIZE
//values should be sorted from (ARRAY_SIZE-1) to 0
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (i+1)) , "Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(ARRAY_SIZE-1-i, Vec3())),
"Got bad SortByKeys value");
}
// this will return everything back to what it was before sorting
Algorithm::SortByKey(keys,values,vtkm::SortGreater());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from ARRAY_SIZE to 1
//values should be sorted from 0 to (ARRAY_SIZE-1)
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
"Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
"Got bad SortByKeys value");
}
//this is here to verify we can sort by vtkm::Vec
Algorithm::SortByKey(values,keys);
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from ARRAY_SIZE to 1
//values should be sorted from 0 to (ARRAY_SIZE-1)
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
"Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
"Got bad SortByKeys value");
}
}
static VTKM_CONT void TestLowerBoundsWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing LowerBounds with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
//verify lower bounds work
Algorithm::LowerBounds(temp,input,handle,vtkm::SortLess());
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i % 50, "Got bad LowerBounds value with SortLess");
}
}
static VTKM_CONT void TestUpperBoundsWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing UpperBounds with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
//verify upper bounds work
Algorithm::UpperBounds(temp,input,handle,vtkm::SortLess());
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == (i % 50)+1, "Got bad UpperBounds value with SortLess");
}
}
static VTKM_CONT void TestUniqueWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Unique with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
Algorithm::Sort(input);
Algorithm::Unique(input, FuseAll());
// Check to make sure that input was resized correctly during Unique.
// (This was a discovered bug at one point.)
input.GetPortalConstControl(); // Forces copy back to control.
input.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
input.GetNumberOfValues() == 1,
"Unique did not resize array (or size did not copy to control).");
vtkm::Id value = input.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == OFFSET, "Got bad unique value");
}
static VTKM_CONT void TestReduce()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce" << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//the output of reduce and scan inclusive should be the same
std::cout << " Reduce with initial value of 0." << std::endl;
vtkm::Id reduce_sum = Algorithm::Reduce(array, vtkm::Id(0));
std::cout << " Reduce with initial value." << std::endl;
vtkm::Id reduce_sum_with_intial_value = Algorithm::Reduce(array,
vtkm::Id(ARRAY_SIZE));
std::cout << " Inclusive scan to check" << std::endl;
vtkm::Id inclusive_sum = Algorithm::ScanInclusive(array, array);
std::cout << " Reduce with 1 value." << std::endl;
array.Shrink(1);
vtkm::Id reduce_sum_one_value = Algorithm::Reduce(array, vtkm::Id(0));
std::cout << " Reduce with 0 values." << std::endl;
array.Shrink(0);
vtkm::Id reduce_sum_no_values = Algorithm::Reduce(array, vtkm::Id(0));
VTKM_TEST_ASSERT(reduce_sum == OFFSET * ARRAY_SIZE,
"Got bad sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum_with_intial_value == reduce_sum + ARRAY_SIZE,
"Got bad sum from Reduce with initial value");
VTKM_TEST_ASSERT(reduce_sum_one_value == OFFSET,
"Got bad single sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum_no_values == 0,
"Got bad empty sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum == inclusive_sum,
"Got different sums from Reduce and ScanInclusive");
}
static VTKM_CONT void TestReduceWithComparisonObject()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with comparison object " << std::endl;
//construct the index array. Assign an abnormally large value
//to the middle of the array, that should be what we see as our sum.
std::vector<vtkm::Id> testData(ARRAY_SIZE);
const vtkm::Id maxValue = ARRAY_SIZE*2;
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
testData[i]= index;
}
testData[ARRAY_SIZE/2] = maxValue;
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
vtkm::Vec<vtkm::Id,2> range = Algorithm::Reduce(input,
vtkm::Vec<vtkm::Id,2>(0,0),
vtkm::MinAndMax<vtkm::Id>());
VTKM_TEST_ASSERT(maxValue == range[1],
"Got bad value from Reduce with comparison object");
VTKM_TEST_ASSERT(0 == range[0],
"Got bad value from Reduce with comparison object");
}
static VTKM_CONT void TestReduceWithFancyArrays()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with ArrayHandleZip" << std::endl;
{
IdArrayHandle keys, values;
Algorithm::Schedule(
ClearArrayKernel(keys.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
ClearArrayKernel(values.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
vtkm::cont::ArrayHandleZip< IdArrayHandle,
IdArrayHandle > zipped(keys,values);
//the output of reduce and scan inclusive should be the same
typedef vtkm::Pair<vtkm::Id,vtkm::Id> ResultType;
ResultType reduce_sum_with_intial_value =
Algorithm::Reduce(zipped, ResultType(ARRAY_SIZE,ARRAY_SIZE));
ResultType expectedResult(OFFSET * ARRAY_SIZE + ARRAY_SIZE,
OFFSET * ARRAY_SIZE + ARRAY_SIZE);
VTKM_TEST_ASSERT( ( reduce_sum_with_intial_value == expectedResult),
"Got bad sum from Reduce with initial value");
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with ArrayHandlePermutation" << std::endl;
{
//lastly test with heterogeneous zip values ( vec3, and constant array handle),
//and a custom reduce binary functor
const vtkm::Id indexLength = 30;
const vtkm::Id valuesLength = 10;
typedef vtkm::Float32 ValueType;
vtkm::Id indexs[indexLength] = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,
5,5,5,1,4,9,7,7,7,8,8,8,0,1,2};
ValueType values[valuesLength] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
6.0f, 7.0f, 8.0f, 9.0f, -2.0f};
const ValueType expectedSum = 125;
IdArrayHandle indexHandle = vtkm::cont::make_ArrayHandle(indexs, indexLength);
vtkm::cont::ArrayHandle<ValueType> valueHandle = vtkm::cont::make_ArrayHandle(values, valuesLength);
vtkm::cont::ArrayHandlePermutation< IdArrayHandle, vtkm::cont::ArrayHandle<ValueType> > perm;
perm = vtkm::cont::make_ArrayHandlePermutation(indexHandle, valueHandle);
const ValueType sum = Algorithm::Reduce(perm, ValueType(0.0f));
std::cout << "sum: " << sum << std::endl;
VTKM_TEST_ASSERT( ( sum == expectedSum),
"Got bad sum from Reduce with permutation handle");
}
}
static VTKM_CONT void TestReduceByKey()
2015-05-04 19:53:35 +00:00
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce By Key" << std::endl;
//first test with very basic integer key / values
{
const vtkm::Id inputLength = 12;
const vtkm::Id expectedLength = 6;
vtkm::Id inputKeys[inputLength] = {0, 0, 0,\
1, 1,\
4,\
0,\
2, 2, 2, 2,\
-1}; // input keys
vtkm::Id inputValues[inputLength] = {13, -2, -1,\
1, 1,\
0,\
3,\
1, 2, 3, 4, \
-42}; // input keys
vtkm::Id expectedKeys[expectedLength] = { 0, 1, 4, 0, 2, -1 };
vtkm::Id expectedValues[expectedLength] = {10, 2, 0, 3, 10, -42};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
2015-05-04 19:53:35 +00:00
IdArrayHandle keysOut, valuesOut;
Algorithm::ReduceByKey( keys,
values,
keysOut,
valuesOut,
vtkm::Add() );
2015-05-04 19:53:35 +00:00
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues[i] == v, "Incorrect reduced value");
2015-05-04 19:53:35 +00:00
}
}
//next test with a single key across the entire set, using vec3 as the
//value, using a custom reduce binary functor
2015-06-01 16:19:17 +00:00
{
const vtkm::Id inputLength = 3;
const vtkm::Id expectedLength = 1;
vtkm::Id inputKeys[inputLength] = {0, 0, 0}; // input keys
vtkm::Vec<vtkm::Float64, 3> inputValues[inputLength];
inputValues[0] = vtkm::make_Vec(13.1, 13.3, 13.5);
inputValues[1] = vtkm::make_Vec(-2.1, -2.3, -2.5);
inputValues[2] = vtkm::make_Vec(-1.0, -1.0, 1.0); // input keys
2015-06-01 16:19:17 +00:00
vtkm::Id expectedKeys[expectedLength] = { 0};
vtkm::Vec<vtkm::Float64, 3> expectedValues[expectedLength];
expectedValues[0] = vtkm::make_Vec(27.51, 30.59, -33.75);
2015-06-01 16:19:17 +00:00
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>, StorageTag> values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
2015-06-01 16:19:17 +00:00
IdArrayHandle keysOut;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>, StorageTag> valuesOut;
Algorithm::ReduceByKey( keys,
values,
keysOut,
valuesOut,
vtkm::Multiply() );
2015-06-01 16:19:17 +00:00
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Vec<vtkm::Float64, 3> v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues[i] == v, "Incorrect reduced vale");
}
}
2015-06-01 16:19:17 +00:00
}
static VTKM_CONT void TestReduceByKeyWithFancyArrays()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce By Key with Fancy Arrays" << std::endl;
//lastly test with heterogeneous zip values ( vec3, and constant array handle),
//and a custom reduce binary functor
2015-06-10 20:37:52 +00:00
const vtkm::Id inputLength = 30;
const vtkm::Id expectedLength = 10;
typedef vtkm::Float32 ValueType;
vtkm::Id inputKeys[inputLength] = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,
5,5,5,6,6,6,7,7,7,8,8,8,9,9,9}; // input keys
ValueType inputValues1[inputLength] = {13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f}; // input values array1
2015-06-10 20:37:52 +00:00
vtkm::Id expectedKeys[expectedLength] = {0,1,2,3,4,5,6,7,8,9};
ValueType expectedValues1[expectedLength] = {10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f}; // output values 1
ValueType expectedValues2[expectedLength] = {3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f}; // output values 2
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
2015-06-10 20:37:52 +00:00
typedef vtkm::cont::ArrayHandle<ValueType, StorageTag> ValueArrayType;
ValueArrayType values1 = vtkm::cont::make_ArrayHandle(inputValues1, inputLength);
2015-06-10 20:37:52 +00:00
typedef vtkm::cont::ArrayHandleConstant<ValueType> ConstValueArrayType;
ConstValueArrayType constOneArray(1.f, inputLength);
vtkm::cont::ArrayHandleZip<ValueArrayType, ConstValueArrayType> valuesZip;
valuesZip = make_ArrayHandleZip(values1, constOneArray); // values in zip
IdArrayHandle keysOut;
ValueArrayType valuesOut1;
ValueArrayType valuesOut2;
vtkm::cont::ArrayHandleZip<ValueArrayType, ValueArrayType> valuesOutZip(valuesOut1, valuesOut2);
Algorithm::ReduceByKey( keys,
valuesZip,
keysOut,
valuesOutZip,
vtkm::Add() );
2015-06-10 20:37:52 +00:00
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOutZip.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Pair<ValueType, ValueType> v = valuesOutZip.GetPortalConstControl().Get(i);
std::cout << "key=" << k << "," << "expectedValues1[i] = " << expectedValues1[i] << "," << "computed value1 = " << v.first << std::endl;
2015-06-10 20:37:52 +00:00
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues1[i] == v.first, "Incorrect reduced value1");
VTKM_TEST_ASSERT( expectedValues2[i] == v.second, "Incorrect reduced value2");
}
2015-05-04 19:53:35 +00:00
}
static VTKM_CONT void TestScanInclusiveByKeyOne()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Inclusive By Key with 1 elements" << std::endl;
const vtkm::Id inputLength = 1;
vtkm::Id inputKeys[inputLength] = {0};
vtkm::Id inputValues[inputLength] = {5};
const vtkm::Id expectedLength = 1;
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanInclusiveByKey(keys, values, valuesOut, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(5 == v, "Incorrect scanned value");
}
static VTKM_CONT void TestScanInclusiveByKeyTwo()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Exclusive By Key with 2 elements" << std::endl;
const vtkm::Id inputLength = 2;
vtkm::Id inputKeys[inputLength] = {0, 1};
vtkm::Id inputValues[inputLength] = {1, 1};
const vtkm::Id expectedLength = 2;
vtkm::Id expectedValues[expectedLength] = {1, 1};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanInclusiveByKey(keys, values, valuesOut, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (auto i = 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
static VTKM_CONT void TestScanInclusiveByKeyLarge()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Inclusive By Key with "
<< ARRAY_SIZE << " elements" << std::endl;
const vtkm::Id inputLength = ARRAY_SIZE;
std::vector<vtkm::Id> inputKeys(inputLength);
for (vtkm::Id i = 0; i < ARRAY_SIZE; i++) {
if (i % 100 < 98)
inputKeys[i] = static_cast<vtkm::Id>(i / 100);
else
inputKeys[i] = static_cast<vtkm::Id>(i);
}
std::vector<vtkm::Id> inputValues(inputLength, 1);
const vtkm::Id expectedLength = ARRAY_SIZE;
std::vector<vtkm::Id> expectedValues(expectedLength);
for (std::size_t i = 0; i < ARRAY_SIZE; i++) {
if (i % 100 < 98)
expectedValues[i] = static_cast<vtkm::Id>(1 + i % 100);
else
expectedValues[i] = static_cast<vtkm::Id>(1);
}
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues);
IdArrayHandle valuesOut;
Algorithm::ScanInclusiveByKey(keys, values, valuesOut, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (auto i = 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
static VTKM_CONT void TestScanInclusiveByKey()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Inclusive By Key" << std::endl;
const vtkm::Id inputLength = 10;
vtkm::Id inputKeys[inputLength] = {0, 0, 0, 1, 1, 2, 3, 3, 3, 3};
vtkm::Id inputValues[inputLength] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const vtkm::Id expectedLength = 10;
vtkm::Id expectedValues[expectedLength] = {1, 2, 3, 1, 2, 1, 1, 2, 3, 4};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanInclusiveByKey(keys, values, valuesOut);
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (auto i = 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
2017-04-13 17:50:56 +00:00
static VTKM_CONT void TestScanExclusiveByKeyOne()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Exclusive By Key with 1 elements" << std::endl;
const vtkm::Id inputLength = 1;
vtkm::Id inputKeys[inputLength] = {0};
vtkm::Id inputValues[inputLength] = {0};
vtkm::Id init = 5;
const vtkm::Id expectedLength = 1;
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanExclusiveByKey(keys, values, valuesOut, init, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(init == v, "Incorrect scanned value");
}
static VTKM_CONT void TestScanExclusiveByKeyTwo()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Exclusive By Key with 2 elements" << std::endl;
const vtkm::Id inputLength = 2;
vtkm::Id inputKeys[inputLength] = {0, 1};
vtkm::Id inputValues[inputLength] = {1, 1};
vtkm::Id init = 5;
const vtkm::Id expectedLength = 2;
vtkm::Id expectedValues[expectedLength] = {5, 5};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanExclusiveByKey(keys, values, valuesOut, init, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (auto i = 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
static VTKM_CONT void TestScanExclusiveByKeyLarge()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Exclusive By Key with "
<< ARRAY_SIZE << " elements" << std::endl;
const vtkm::Id inputLength = ARRAY_SIZE;
std::vector<vtkm::Id> inputKeys(inputLength);
for (std::size_t i = 0; i < ARRAY_SIZE; i++) {
if (i % 100 < 98)
inputKeys[i] = static_cast<vtkm::Id>(i / 100);
else
inputKeys[i] = static_cast<vtkm::Id>(i);
}
std::vector<vtkm::Id> inputValues(inputLength, 1);
vtkm::Id init = 5;
const vtkm::Id expectedLength = ARRAY_SIZE;
std::vector<vtkm::Id> expectedValues(expectedLength);
for (std::size_t i = 0; i < ARRAY_SIZE; i++) {
if (i % 100 < 98)
expectedValues[i] = static_cast<vtkm::Id>(init + i % 100);
else
expectedValues[i] = init;
}
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues);
IdArrayHandle valuesOut;
Algorithm::ScanExclusiveByKey(keys, values, valuesOut, init, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (std::size_t i= 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
static VTKM_CONT void TestScanExclusiveByKey()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Scan Exclusive By Key" << std::endl;
const vtkm::Id inputLength = 10;
vtkm::Id inputKeys[inputLength] = {0, 0, 0, 1, 1, 2, 3, 3, 3, 3};
vtkm::Id inputValues[inputLength] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
vtkm::Id init = 5;
const vtkm::Id expectedLength = 10;
vtkm::Id expectedValues[expectedLength] = {5, 6, 7, 5, 6, 5, 5, 6, 7, 8};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle valuesOut;
Algorithm::ScanExclusiveByKey(keys, values, valuesOut, init, vtkm::Add());
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for (std::size_t i= 0; i < expectedLength; i++) {
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(expectedValues[i] == v, "Incorrect scanned value");
}
}
2017-04-13 17:50:56 +00:00
static VTKM_CONT void TestScanInclusive()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan" << std::endl;
{
std::cout << " size " << ARRAY_SIZE << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//we know have an array whose sum is equal to OFFSET * ARRAY_SIZE,
//let's validate that
vtkm::Id sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET * ARRAY_SIZE,
"Got bad sum from Inclusive Scan");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id value = array.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == (i+1) * OFFSET,
"Incorrect partial sum");
}
std::cout << " size 1" << std::endl;
array.Shrink(1);
sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET, "Incorrect partial sum");
const vtkm::Id value = array.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == OFFSET, "Incorrect partial sum");
std::cout << " size 0" << std::endl;
array.Shrink(0);
sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == 0, "Incorrect partial sum");
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with multiplication operator" << std::endl;
{
std::vector<vtkm::Float64> inputValues(ARRAY_SIZE);
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
{
inputValues[i] = 1.01;
}
std::size_t mid = ARRAY_SIZE/2;
inputValues[mid] = 0.0;
vtkm::cont::ArrayHandle<vtkm::Float64> array =
vtkm::cont::make_ArrayHandle(&inputValues[0], ARRAY_SIZE);
vtkm::Float64 product = Algorithm::ScanInclusive(array, array,
vtkm::Multiply());
VTKM_TEST_ASSERT(product == 0.0f, "ScanInclusive product result not 0.0");
for (std::size_t i = 0; i < mid; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
vtkm::Float64 expected = pow(1.01, static_cast<vtkm::Float64>(i + 1));
vtkm::Float64 got = array.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(test_equal(got, expected),
"Incorrect results for ScanInclusive");
}
for (std::size_t i = mid; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(index) == 0.0f,
"Incorrect results for ScanInclusive");
}
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with a vtkm::Vec" << std::endl;
{
typedef vtkm::Vec<Float64,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64,3>,StorageTag>
Vec3ArrayHandle;
std::vector<Vec3> testValues(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testValues[i] = TestValue(1, Vec3());
}
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Vec3 sum = Algorithm::ScanInclusive(values, values);
std::cout << "Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT( test_equal(sum, TestValue(1, Vec3()) * ARRAY_SIZE ),
"Got bad sum from Inclusive Scan");
}
}
static VTKM_CONT void TestScanInclusiveWithComparisonObject()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with comparison object " << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
AddArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//we know have an array whose sum is equal to OFFSET * ARRAY_SIZE,
//let's validate that
IdArrayHandle result;
vtkm::Id sum = Algorithm::ScanInclusive(array,
result,
vtkm::Maximum());
VTKM_TEST_ASSERT(sum == OFFSET + (ARRAY_SIZE-1),
"Got bad sum from Inclusive Scan with comparison object");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id input_value = array.GetPortalConstControl().Get(i);
const vtkm::Id result_value = result.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(input_value == result_value, "Incorrect partial sum");
}
//now try it inline
sum = Algorithm::ScanInclusive(array,
array,
vtkm::Maximum());
VTKM_TEST_ASSERT(sum == OFFSET + (ARRAY_SIZE-1),
"Got bad sum from Inclusive Scan with comparison object");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id input_value = array.GetPortalConstControl().Get(i);
const vtkm::Id result_value = result.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(input_value == result_value, "Incorrect partial sum");
}
}
static VTKM_CONT void TestScanExclusive()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan" << std::endl;
{
std::cout << " size " << ARRAY_SIZE << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
// we know have an array whose sum = (OFFSET * ARRAY_SIZE),
// let's validate that
vtkm::Id sum = Algorithm::ScanExclusive(array, array);
std::cout << " Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT(sum == (OFFSET * ARRAY_SIZE),
"Got bad sum from Exclusive Scan");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id value = array.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i * OFFSET,
"Incorrect partial sum");
}
std::cout << " size 1" << std::endl;
array.Shrink(1);
array.GetPortalControl().Set(0, OFFSET);
sum = Algorithm::ScanExclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET, "Incorrect partial sum");
const vtkm::Id value = array.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == 0, "Incorrect partial sum");
std::cout << " size 0" << std::endl;
array.Shrink(0);
sum = Algorithm::ScanExclusive(array, array);
VTKM_TEST_ASSERT(sum == 0, "Incorrect partial sum");
}
// Enable when Exclusive Scan with custom operator is implemented for all
// device adaptors
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan with multiplication operator" << std::endl;
{
std::vector<vtkm::Float64> inputValues(ARRAY_SIZE);
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
{
inputValues[i] = 1.01;
}
std::size_t mid = ARRAY_SIZE/2;
inputValues[mid] = 0.0;
vtkm::cont::ArrayHandle<vtkm::Float64> array = vtkm::cont::make_ArrayHandle(inputValues);
vtkm::Float64 initialValue = 2.00;
vtkm::Float64 product = Algorithm::ScanExclusive(array, array,
vtkm::Multiply(), initialValue);
VTKM_TEST_ASSERT(product == 0.0f, "ScanExclusive product result not 0.0");
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(0) == initialValue,
"ScanExclusive result's first value != initialValue");
for (std::size_t i = 1; i <= mid; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
vtkm::Float64 expected = pow(1.01, static_cast<vtkm::Float64>(i)) *
initialValue;
vtkm::Float64 got = array.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(test_equal(got, expected),
"Incorrect results for ScanExclusive");
}
for (std::size_t i = mid + 1; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(index) == 0.0f,
"Incorrect results for ScanExclusive");
}
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan with a vtkm::Vec" << std::endl;
{
typedef vtkm::Vec<Float64,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64,3>,StorageTag>
Vec3ArrayHandle;
std::vector<Vec3> testValues(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testValues[i] = TestValue(1, Vec3());
}
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Vec3 sum = Algorithm::ScanExclusive(values, values);
std::cout << "Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT( test_equal(sum, (TestValue(1, Vec3()) * ARRAY_SIZE) ),
"Got bad sum from Exclusive Scan");
}
}
static VTKM_CONT void TestErrorExecution()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exceptions in Execution Environment" << std::endl;
std::cout << "Generating one error." << std::endl;
std::string message;
try
{
Algorithm::Schedule(OneErrorKernel(), ARRAY_SIZE);
}
2017-02-23 15:13:30 +00:00
catch (vtkm::cont::ErrorExecution &error)
{
std::cout << "Got expected error: " << error.GetMessage() << std::endl;
message = error.GetMessage();
}
VTKM_TEST_ASSERT(message == ERROR_MESSAGE,
"Did not get expected error message.");
std::cout << "Generating lots of errors." << std::endl;
message = "";
try
{
Algorithm::Schedule(AllErrorKernel(), ARRAY_SIZE);
}
2017-02-23 15:13:30 +00:00
catch (vtkm::cont::ErrorExecution &error)
{
std::cout << "Got expected error: " << error.GetMessage() << std::endl;
message = error.GetMessage();
}
VTKM_TEST_ASSERT(message == ERROR_MESSAGE,
"Did not get expected error message.");
}
2016-05-12 09:59:54 +00:00
template <typename T, int N=0>
struct TestCopy {};
template <typename T>
struct TestCopy<T> {
static T get(vtkm::Id i) { return static_cast<T>(i); }
};
template <typename T, int N>
2016-05-10 19:22:55 +00:00
struct TestCopy<vtkm::Vec<T, N> > {
2016-05-12 09:59:54 +00:00
static vtkm::Vec<T, N> get(vtkm::Id i) {
vtkm::Vec<T, N> temp;
for (int j=0; j<N; ++j) {
2016-05-10 19:22:55 +00:00
temp[j] = static_cast<T>( OFFSET+(i % 50) );
2016-05-12 09:59:54 +00:00
}
return temp;
}
};
template <typename T>
static VTKM_CONT void TestCopyArrays()
2016-05-12 09:59:54 +00:00
{
#define COPY_ARRAY_SIZE 10000
std::vector<T> testData(COPY_ARRAY_SIZE);
vtkm::Id index = 0;
for(std::size_t i=0; i < COPY_ARRAY_SIZE; ++i, ++index)
2016-05-12 09:59:54 +00:00
{
testData[i]= TestCopy<T>::get(index);
2016-05-12 09:59:54 +00:00
}
vtkm::cont::ArrayHandle<T> input = vtkm::cont::make_ArrayHandle(&testData[0],
COPY_ARRAY_SIZE);
2016-05-12 09:59:54 +00:00
//make a deep copy of input and place it into temp
{
2016-05-12 09:59:54 +00:00
vtkm::cont::ArrayHandle<T> temp;
temp.Allocate( COPY_ARRAY_SIZE * 2 );
2016-05-12 09:59:54 +00:00
Algorithm::Copy(input,temp);
VTKM_TEST_ASSERT(temp.GetNumberOfValues() == COPY_ARRAY_SIZE,
"Copy Needs to Resize Array");
2016-05-12 09:59:54 +00:00
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
2016-05-12 09:59:54 +00:00
{
T value = temp.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (Copy)");
2016-05-12 09:59:54 +00:00
}
}
//Verify copy of empty array works
{
vtkm::cont::ArrayHandle<T> tempIn;
vtkm::cont::ArrayHandle<T> tempOut;
tempOut.Allocate(COPY_ARRAY_SIZE);
Algorithm::Copy(tempIn, tempOut);
VTKM_TEST_ASSERT(tempIn.GetNumberOfValues() == tempOut.GetNumberOfValues(),
"Copy sized wrong");
// Actually allocate input array to 0 in case that makes a difference.
tempIn.Allocate(0);
tempOut.Allocate(COPY_ARRAY_SIZE);
Algorithm::Copy(tempIn, tempOut);
VTKM_TEST_ASSERT(tempIn.GetNumberOfValues() == tempOut.GetNumberOfValues(),
"Copy sized wrong");
}
//CopySubRange tests:
//1. Verify invalid input start position fails
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, COPY_ARRAY_SIZE*4, 1, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange when given bad input offset");
}
//2. Verify unallocated output gets allocated
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange should succeed");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == COPY_ARRAY_SIZE,
"CopySubRange needs to allocate output");
}
//3. Verify under allocated output gets resized properly
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate(2);
bool result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange should succeed");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == COPY_ARRAY_SIZE,
"CopySubRange needs to re-allocate output");
}
//4. Verify invalid input length gets shortened
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, 100, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange needs to shorten input range");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE-100),
"CopySubRange needs to shorten input range");
typename std::vector<T>::const_iterator c = testData.begin() + 100;
for(vtkm::Id i=0; i < (COPY_ARRAY_SIZE-100); i+=100,c+=100)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 2)");
}
}
//5. Verify sub range copy works when copying into a larger output
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate( COPY_ARRAY_SIZE * 2 );
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, COPY_ARRAY_SIZE);
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE*2),
"CopySubRange needs to not resize array");
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 5)");
value = output.GetPortalConstControl().Get(COPY_ARRAY_SIZE + i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 5)");
}
}
//6. Verify that whey sub range needs to reallocate the output it
// properly copies the original data instead of clearing it
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate( COPY_ARRAY_SIZE );
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, COPY_ARRAY_SIZE);
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE*2),
"CopySubRange needs too resize Array");
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 6)");
value = output.GetPortalConstControl().Get(COPY_ARRAY_SIZE + i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 6)");
}
}
{
vtkm::cont::ArrayHandle<T> output;
//7. Verify negative input index returns false
bool result = Algorithm::CopySubRange(input, -1, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative index should fail");
//8. Verify negative input numberOfElementsToCopy returns false
result = Algorithm::CopySubRange(input, 0, -COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative number elements should fail");
//9. Verify negative output index return false
result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, -2);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative output index should fail");
}
#undef COPY_ARRAY_SIZE
2016-05-12 09:59:54 +00:00
}
static VTKM_CONT void TestCopyArraysMany()
2016-05-12 09:59:54 +00:00
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Copy to same array type" << std::endl;
2016-05-10 19:22:55 +00:00
TestCopyArrays< vtkm::Vec<vtkm::Float32,4> >();
TestCopyArrays< vtkm::Vec<vtkm::Float64,4> >();
2016-05-12 09:59:54 +00:00
//
2016-05-10 19:22:55 +00:00
TestCopyArrays< vtkm::Vec<vtkm::UInt8,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt16,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt32,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt64,2> >();
2016-05-12 09:59:54 +00:00
//
2016-05-10 19:22:55 +00:00
TestCopyArrays< vtkm::Float32 >();
TestCopyArrays< vtkm::Float64 >();
2016-05-12 09:59:54 +00:00
//
2016-05-10 19:22:55 +00:00
TestCopyArrays< vtkm::Int8 >();
TestCopyArrays< vtkm::Int16 >();
TestCopyArrays< vtkm::Int32 >();
TestCopyArrays< vtkm::Int64 >();
2016-05-12 09:59:54 +00:00
//
2016-05-10 19:22:55 +00:00
TestCopyArrays< vtkm::UInt8 >();
TestCopyArrays< vtkm::UInt16 >();
TestCopyArrays< vtkm::UInt32 >();
TestCopyArrays< vtkm::UInt64 >();
2016-05-12 09:59:54 +00:00
//
TestCopyArrays<vtkm::Id>();
}
static VTKM_CONT void TestCopyArraysInDiffTypes()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Copy to a different array type" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
vtkm::cont::ArrayHandle<vtkm::Float64> temp;
Algorithm::Copy(input,temp);
std::vector<vtkm::Id>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i, ++c)
{
vtkm::Float64 value = temp.GetPortalConstControl().Get(i);
2017-01-10 16:36:51 +00:00
VTKM_TEST_ASSERT(value == static_cast<vtkm::Float64>(*c),
"Got bad value (Copy)");
}
}
static VTKM_CONT void TestAtomicArray()
2016-02-10 15:51:31 +00:00
{
//we can't use ARRAY_SIZE as that would cause a overflow
vtkm::Int32 SHORT_ARRAY_SIZE = 10000;
vtkm::Int32 atomicCount = 0;
for(vtkm::Int32 i = 0; i < SHORT_ARRAY_SIZE; i++) atomicCount += i;
2016-02-10 16:21:38 +00:00
std::cout << "-------------------------------------------" << std::endl;
// To test the atomics, SHORT_ARRAY_SIZE number of threads will all increment
2016-02-10 15:51:31 +00:00
// a single atomic value.
std::cout << "Testing Atomic Add with vtkm::Int32" << std::endl;
2016-02-10 15:51:31 +00:00
{
std::vector<vtkm::Int32> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
2016-02-10 15:51:31 +00:00
vtkm::Int32 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic add Int32");
}
std::cout << "Testing Atomic Add with vtkm::Int64" << std::endl;
2016-02-10 15:51:31 +00:00
{
std::vector<vtkm::Int64> singleElement;
2016-02-10 15:51:31 +00:00
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
2016-02-10 15:51:31 +00:00
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
vtkm::Int64 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic add Int64");
2016-02-10 15:51:31 +00:00
}
std::cout << "Testing Atomic CAS with vtkm::Int32" << std::endl;
2016-02-10 15:51:31 +00:00
{
std::vector<vtkm::Int32> singleElement;
2016-02-10 15:51:31 +00:00
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
2016-02-10 15:51:31 +00:00
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
vtkm::Int32 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic CAS Int32");
2016-02-10 15:51:31 +00:00
}
std::cout << "Testing Atomic CAS with vtkm::Int64" << std::endl;
2016-02-10 15:51:31 +00:00
{
std::vector<vtkm::Int64> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
2016-02-10 15:51:31 +00:00
vtkm::Int64 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic CAS Int64");
2016-02-10 15:51:31 +00:00
}
2016-02-10 15:51:31 +00:00
}
struct TestAll
{
VTKM_CONT void operator()() const
{
std::cout << "Doing DeviceAdapter tests" << std::endl;
TestArrayManagerExecution();
TestOutOfMemory();
TestTimer();
TestRuntime();
TestAlgorithmSchedule();
TestErrorExecution();
TestReduce();
TestReduceWithComparisonObject();
TestReduceWithFancyArrays();
2015-05-04 19:53:35 +00:00
TestReduceByKey();
TestReduceByKeyWithFancyArrays();
2015-05-04 19:53:35 +00:00
TestScanExclusive();
TestScanInclusive();
TestScanInclusiveWithComparisonObject();
TestScanInclusiveByKeyOne();
TestScanInclusiveByKeyTwo();
TestScanInclusiveByKeyLarge();
TestScanInclusiveByKey();
TestScanExclusiveByKeyOne();
TestScanExclusiveByKeyTwo();
TestScanExclusiveByKeyLarge();
TestScanExclusiveByKey();
2017-04-13 17:50:56 +00:00
TestSort();
TestSortWithComparisonObject();
TestSortWithFancyArrays();
TestSortByKey();
TestLowerBoundsWithComparisonObject();
TestUpperBoundsWithComparisonObject();
TestUniqueWithComparisonObject();
TestOrderedUniqueValues(); //tests Copy, LowerBounds, Sort, Unique
TestCopyIf();
2016-05-12 09:59:54 +00:00
TestCopyArraysMany();
TestCopyArraysInDiffTypes();
2016-02-10 15:51:31 +00:00
TestAtomicArray();
}
};
public:
/// Run a suite of tests to check to see if a DeviceAdapter properly supports
/// all members and classes required for driving vtkm algorithms. Returns an
/// error code that can be returned from the main function of a test.
///
static VTKM_CONT int Run()
{
return vtkm::cont::testing::Testing::Run(TestAll());
}
};
#undef ERROR_MESSAGE
#undef ARRAY_SIZE
#undef OFFSET
#undef DIM
}
}
} // namespace vtkm::cont::testing
#endif //vtk_m_cont_testing_TestingDeviceAdapter_h