Merge remote-tracking branch 'upstream/master' into Enhance-Testing-From-File

This commit is contained in:
James 2020-03-12 10:10:03 -04:00
commit 8579d54cb9
766 changed files with 27361 additions and 30579 deletions

@ -47,7 +47,7 @@ target_compile_features(vtkm_compiler_flags INTERFACE cxx_std_11)
# to have the smallest binary impact as they can drop any VTK-m symbol
# they don't use.
if(VTKM_COMPILER_IS_MSVC)
target_compile_options(vtkm_compiler_flags INTERFACE /Gy)
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CXX>:/Gy>)
if(TARGET vtkm::cuda)
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler="/Gy">)
endif()

@ -110,6 +110,35 @@ function(vtkm_declare_headers)
vtkm_install_headers("${dir_prefix}" ${ARGN})
endfunction(vtkm_declare_headers)
#-----------------------------------------------------------------------------
function(vtkm_setup_job_pool)
# The VTK-m job pool is only used for components that use large amounts
# of memory such as worklet tests, filters, and filter tests
get_property(vtkm_pool_established
GLOBAL PROPERTY VTKM_JOB_POOL_ESTABLISHED SET)
if(NOT vtkm_pool_established)
# The VTK-m filters uses large amounts of memory to compile as it does lots
# of template expansion. To reduce the amount of tension on the machine when
# using generators such as ninja we restrict the number of VTK-m enabled
# compilation units to be built at the same time.
#
# We try to allocate a pool size where we presume each compilation process
# will require 3GB of memory. To allow for other NON VTK-m jobs we leave at
# least 3GB of memory as 'slop'.
cmake_host_system_information(RESULT vtkm_mem_ QUERY TOTAL_PHYSICAL_MEMORY)
math(EXPR vtkm_pool_size "(${vtkm_mem_}/3072)-1")
if (vtkm_pool_size LESS 1)
set(vtkm_pool_size 1)
endif ()
set_property(GLOBAL APPEND
PROPERTY
JOB_POOLS vtkm_pool=${vtkm_pool_size})
set_property(GLOBAL PROPERTY VTKM_JOB_POOL_ESTABLISHED TRUE)
endif()
endfunction()
#-----------------------------------------------------------------------------
# FORWARD FACING API
@ -313,10 +342,11 @@ endfunction()
# SOURCES <source_list>
# TEMPLATE_SOURCES <.hxx >
# HEADERS <header list>
# USE_VTKM_JOB_POOL
# [ DEVICE_SOURCES <source_list> ]
# )
function(vtkm_library)
set(options OBJECT STATIC SHARED)
set(options OBJECT STATIC SHARED USE_VTKM_JOB_POOL)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES HEADERS TEMPLATE_SOURCES DEVICE_SOURCES)
cmake_parse_arguments(VTKm_LIB
@ -357,7 +387,6 @@ function(vtkm_library)
set_property(TARGET ${lib_name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
set_property(TARGET ${lib_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH})
# allow the static cuda runtime find the driver (libcuda.dyllib) at runtime.
if(APPLE)
set_property(TARGET ${lib_name} PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
@ -402,4 +431,9 @@ function(vtkm_library)
RUNTIME DESTINATION ${VTKm_INSTALL_BIN_DIR}
)
if(VTKm_LIB_USE_VTKM_JOB_POOL)
vtkm_setup_job_pool()
set_property(TARGET ${lib_name} PROPERTY JOB_POOL_COMPILE vtkm_pool)
endif()
endfunction(vtkm_library)

@ -22,6 +22,7 @@ include(VTKmWrappers)
# TEST_ARGS <argument_list>
# MPI
# ALL_BACKENDS
# USE_VTKM_JOB_POOL
# <options>
# )
#
@ -46,7 +47,7 @@ function(vtkm_unit_tests)
endif()
set(options)
set(global_options ${options} MPI ALL_BACKENDS)
set(global_options ${options} USE_VTKM_JOB_POOL MPI ALL_BACKENDS)
set(oneValueArgs BACKEND NAME LABEL)
set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
cmake_parse_arguments(VTKm_UT
@ -143,6 +144,11 @@ function(vtkm_unit_tests)
target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
if(VTKm_UT_USE_VTKM_JOB_POOL)
vtkm_setup_job_pool()
set_property(TARGET ${test_prog} PROPERTY JOB_POOL_COMPILE vtkm_pool)
endif()
list(LENGTH per_device_command_line_arguments number_of_devices)
foreach(index RANGE ${number_of_devices})
if(index EQUAL number_of_devices)

@ -128,12 +128,17 @@ set(VTKm_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
# and the warnings are too strict for the parent project.
vtkm_option(VTKm_ENABLE_DEVELOPER_FLAGS "Enable compiler flags that are useful while developing VTK-m" ON)
# By default VTK-m would install its README.md and LICENSE.md.
# Some application might need not to install those, hence this option.
vtkm_option(VTKm_NO_INSTALL_README_LICENSE "disable the installation of README and LICENSE files" OFF)
mark_as_advanced(
VTKm_ENABLE_LOGGING
VTKm_NO_ASSERT
VTKm_INSTALL_ONLY_LIBRARIES
VTKm_USE_DEFAULT_SYMBOL_VISIBILITY
VTKm_ENABLE_DEVELOPER_FLAGS
VTKm_NO_INSTALL_README_LICENSE
)
#-----------------------------------------------------------------------------
@ -226,6 +231,18 @@ write_basic_package_version_file(
VERSION ${VTKm_VERSION}
COMPATIBILITY ExactVersion )
# Install the readme and license files.
if (NOT VTKm_NO_INSTALL_README_LICENSE)
install(FILES ${VTKm_SOURCE_DIR}/README.md
DESTINATION ${VTKm_INSTALL_SHARE_DIR}
RENAME VTKmREADME.md
)
install(FILES ${VTKm_SOURCE_DIR}/LICENSE.txt
DESTINATION ${VTKm_INSTALL_SHARE_DIR}
RENAME VTKmLICENSE.txt
)
endif()
if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
install(
FILES
@ -234,16 +251,6 @@ if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
DESTINATION ${VTKm_INSTALL_CONFIG_DIR}
)
# Install the readme and license files.
install(FILES ${VTKm_SOURCE_DIR}/README.md
DESTINATION ${VTKm_INSTALL_SHARE_DIR}
RENAME VTKmREADME.md
)
install(FILES ${VTKm_SOURCE_DIR}/LICENSE.txt
DESTINATION ${VTKm_INSTALL_SHARE_DIR}
RENAME VTKmLICENSE.txt
)
# Install helper configure files.
install(
FILES

@ -28,6 +28,12 @@ You can find out more about the design of VTK-m on the [VTK-m Wiki].
+ "Part 4: Advanced Development" covers topics such as new worklet
types and custom device adapters.
+ A practical [VTK-m Tutorial] based in what users want to accomplish with
VTK-m:
+ Building VTK-m and using existing VTK-m data structures and filters.
+ Algorithm development with VTK-m.
+ Writing new VTK-m filters.
+ Community discussion takes place on the [VTK-m users email list].
+ Doxygen-generated nightly reference documentation is available
@ -149,6 +155,19 @@ Below is a simple example of using VTK-m to load a VTK image file, run the
Marching Cubes algorithm on it, and render the results to an image:
```cpp
#include <vtkm/Bounds.h>
#include <vtkm/Range.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/filter/Contour.h>
#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/rendering/Actor.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/MapperRayTracer.h>
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/View3D.h>
vtkm::io::reader::VTKDataSetReader reader("path/to/vtk_image_file");
vtkm::cont::DataSet inputData = reader.ReadDataSet();
std::string fieldName = "scalars";
@ -165,21 +184,10 @@ vtkm::cont::DataSet outputData = filter.Execute(inputData);
// compute the bounds and extends of the input data
vtkm::Bounds coordsBounds = inputData.GetCoordinateSystem().GetBounds();
vtkm::Vec<vtkm::Float64,3> totalExtent( coordsBounds.X.Length(),
coordsBounds.Y.Length(),
coordsBounds.Z.Length() );
vtkm::Float64 mag = vtkm::Magnitude(totalExtent);
vtkm::Normalize(totalExtent);
// setup a camera and point it to towards the center of the input data
vtkm::rendering::Camera camera;
camera.ResetToBounds(coordsBounds);
camera.SetLookAt(totalExtent*(mag * .5f));
camera.SetViewUp(vtkm::make_Vec(0.f, 1.f, 0.f));
camera.SetClippingRange(1.f, 100.f);
camera.SetFieldOfView(60.f);
camera.SetPosition(totalExtent*(mag * 2.f));
vtkm::cont::ColorTable colorTable("inferno");
// Create a mapper, canvas and view that will be used to render the scene
@ -199,6 +207,19 @@ view.Paint();
view.SaveAs("demo_output.pnm");
```
A minimal CMakeLists.txt such as the following one can be used to build this
example.
```CMake
project(example)
set(VTKm_DIR "/somepath/lib/cmake/vtkm-XYZ")
find_package(VTKm REQUIRED)
add_executable(example example.cxx)
target_link_libraries(example vtkm_cont vtkm_rendering)
```
## License ##
@ -216,4 +237,5 @@ See [LICENSE.txt](LICENSE.txt) for details.
[VTK-m Users Guide]: http://m.vtk.org/images/c/c8/VTKmUsersGuide.pdf
[VTK-m users email list]: http://vtk.org/mailman/listinfo/vtkm
[VTK-m Wiki]: http://m.vtk.org/
[VTK-m Tutorial]: http://m.vtk.org/index.php/Tutorial
[CONTRIBUTING.md]: CONTRIBUTING.md

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -8,23 +8,19 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/TypeTraits.h>
#include "Benchmarker.h"
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/internal/Configure.h>
#include <vtkm/testing/Testing.h>
#include <iomanip>
#include <iostream>
#include <vtkm/List.h>
#include <sstream>
#ifdef VTKM_ENABLE_TBB
@ -34,145 +30,78 @@
// For the TBB implementation, the number of threads can be customized using a
// "NumThreads [numThreads]" argument.
namespace vtkm
{
namespace benchmarking
{
const vtkm::UInt64 COPY_SIZE_MIN = (1 << 10); // 1 KiB
const vtkm::UInt64 COPY_SIZE_MAX = (1 << 29); // 512 MiB
const vtkm::UInt64 COPY_SIZE_INC = 1; // Used as 'size <<= INC'
const size_t COL_WIDTH = 32;
template <typename ValueType, typename DeviceAdapter>
struct MeasureCopySpeed
{
using Algo = vtkm::cont::Algorithm;
vtkm::cont::ArrayHandle<ValueType> Source;
vtkm::cont::ArrayHandle<ValueType> Destination;
vtkm::UInt64 NumBytes;
VTKM_CONT
MeasureCopySpeed(vtkm::UInt64 bytes)
: NumBytes(bytes)
{
vtkm::Id numValues = static_cast<vtkm::Id>(bytes / sizeof(ValueType));
this->Source.Allocate(numValues);
}
VTKM_CONT vtkm::Float64 operator()()
{
vtkm::cont::Timer timer{ DeviceAdapter() };
timer.Start();
Algo::Copy(this->Source, this->Destination);
return timer.GetElapsedTime();
}
VTKM_CONT std::string Description() const
{
vtkm::UInt64 actualSize = sizeof(ValueType);
actualSize *= static_cast<vtkm::UInt64>(this->Source.GetNumberOfValues());
std::ostringstream out;
out << "Copying " << vtkm::cont::GetHumanReadableSize(this->NumBytes)
<< " (actual=" << vtkm::cont::GetHumanReadableSize(actualSize) << ") of "
<< vtkm::testing::TypeName<ValueType>::Name() << "\n";
return out.str();
}
};
void PrintRow(std::ostream& out, const std::string& label, const std::string& data)
{
out << "| " << std::setw(COL_WIDTH) << label << " | " << std::setw(COL_WIDTH) << data << " |"
<< std::endl;
}
void PrintDivider(std::ostream& out)
{
const std::string fillStr(COL_WIDTH, '-');
out << "|-" << fillStr << "-|-" << fillStr << "-|" << std::endl;
}
template <typename ValueType, typename DeviceAdapter>
void BenchmarkValueType(vtkm::cont::DeviceAdapterId id)
{
PrintRow(std::cout, vtkm::testing::TypeName<ValueType>::Name(), id.GetName());
PrintDivider(std::cout);
Benchmarker bench(15, 100);
for (vtkm::UInt64 size = COPY_SIZE_MIN; size <= COPY_SIZE_MAX; size <<= COPY_SIZE_INC)
{
MeasureCopySpeed<ValueType, DeviceAdapter> functor(size);
bench.Reset();
std::string speedStr;
try
{
bench.GatherSamples(functor);
vtkm::Float64 speed = static_cast<Float64>(size) / stats::Mean(bench.GetSamples());
speedStr = vtkm::cont::GetHumanReadableSize(static_cast<UInt64>(speed)) + std::string("/s");
}
catch (vtkm::cont::ErrorBadAllocation&)
{
speedStr = "[allocation too large]";
}
PrintRow(std::cout, vtkm::cont::GetHumanReadableSize(size), speedStr);
}
std::cout << "\n";
}
}
} // end namespace vtkm::benchmarking
namespace
{
using namespace vtkm::benchmarking;
struct BenchmarkValueTypeFunctor
// Make this global so benchmarks can access the current device id:
vtkm::cont::InitializeResult Config;
const vtkm::UInt64 COPY_SIZE_MIN = (1 << 10); // 1 KiB
const vtkm::UInt64 COPY_SIZE_MAX = (1 << 30); // 1 GiB
using TypeList = vtkm::List<vtkm::UInt8,
vtkm::Vec2ui_8,
vtkm::Vec3ui_8,
vtkm::Vec4ui_8,
vtkm::UInt32,
vtkm::Vec2ui_32,
vtkm::UInt64,
vtkm::Vec2ui_64,
vtkm::Float32,
vtkm::Vec2f_32,
vtkm::Float64,
vtkm::Vec2f_64,
vtkm::Pair<vtkm::UInt32, vtkm::Float32>,
vtkm::Pair<vtkm::UInt32, vtkm::Float64>,
vtkm::Pair<vtkm::UInt64, vtkm::Float32>,
vtkm::Pair<vtkm::UInt64, vtkm::Float64>>;
template <typename ValueType>
void CopySpeed(benchmark::State& state)
{
template <typename DeviceAdapter>
bool operator()(DeviceAdapter id)
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::UInt64 numBytes = static_cast<vtkm::UInt64>(state.range(0));
const vtkm::Id numValues = static_cast<vtkm::Id>(numBytes / sizeof(ValueType));
state.SetLabel(vtkm::cont::GetHumanReadableSize(numBytes));
vtkm::cont::ArrayHandle<ValueType> src;
vtkm::cont::ArrayHandle<ValueType> dst;
src.Allocate(numValues);
dst.Allocate(numValues);
vtkm::cont::Timer timer(device);
for (auto _ : state)
{
BenchmarkValueType<vtkm::UInt8, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec2ui_8, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec3ui_8, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec4ui_8, DeviceAdapter>(id);
(void)_;
timer.Start();
vtkm::cont::Algorithm::Copy(device, src, dst);
timer.Stop();
BenchmarkValueType<vtkm::UInt32, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec2ui_32, DeviceAdapter>(id);
BenchmarkValueType<vtkm::UInt64, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec2ui_64, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Float32, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec2f_32, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Float64, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Vec2f_64, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Pair<vtkm::UInt32, vtkm::Float32>, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Pair<vtkm::UInt32, vtkm::Float64>, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Pair<vtkm::UInt64, vtkm::Float32>, DeviceAdapter>(id);
BenchmarkValueType<vtkm::Pair<vtkm::UInt64, vtkm::Float64>, DeviceAdapter>(id);
return true;
state.SetIterationTime(timer.GetElapsedTime());
}
};
const int64_t iterations = static_cast<int64_t>(state.iterations());
state.SetBytesProcessed(static_cast<int64_t>(numBytes) * iterations);
state.SetItemsProcessed(static_cast<int64_t>(numValues) * iterations);
}
VTKM_BENCHMARK_TEMPLATES_OPTS(CopySpeed,
->Range(COPY_SIZE_MIN, COPY_SIZE_MAX)
->ArgName("Bytes"),
TypeList);
} // end anon namespace
int main(int argc, char* argv[])
{
auto opts = vtkm::cont::InitializeOptions::RequireDevice |
vtkm::cont::InitializeOptions::ErrorOnBadOption | vtkm::cont::InitializeOptions::AddHelp;
auto config = vtkm::cont::Initialize(argc, argv, opts);
// Parse VTK-m options:
auto opts = vtkm::cont::InitializeOptions::RequireDevice | vtkm::cont::InitializeOptions::AddHelp;
Config = vtkm::cont::Initialize(argc, argv, opts);
// Setup device:
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
// Handle NumThreads command-line arg:
#ifdef VTKM_ENABLE_TBB
int numThreads = tbb::task_scheduler_init::automatic;
#endif // TBB
@ -196,6 +125,6 @@ int main(int argc, char* argv[])
tbb::task_scheduler_init init(numThreads);
#endif // TBB
BenchmarkValueTypeFunctor functor;
vtkm::cont::TryExecuteOnDevice(config.Device, functor);
// handle benchmarking related args and run benchmarks:
VTKM_EXECUTE_BENCHMARKS(argc, argv);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -14,6 +14,7 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
@ -31,114 +32,97 @@
#include <string>
#include <vector>
using namespace vtkm::benchmarking;
namespace vtkm
{
namespace benchmarking
namespace
{
template <typename Precision, typename DeviceAdapter>
struct BenchRayTracing
// Hold configuration state (e.g. active device)
vtkm::cont::InitializeResult Config;
void BenchRayTracing(::benchmark::State& state)
{
vtkm::rendering::raytracing::RayTracer Tracer;
vtkm::rendering::raytracing::Camera RayCamera;
vtkm::cont::ArrayHandle<vtkm::Id4> Indices;
vtkm::rendering::raytracing::Ray<Precision> Rays;
vtkm::cont::CoordinateSystem Coords;
vtkm::cont::DataSet Data;
const vtkm::Id3 dims(128, 128, 128);
VTKM_CONT ~BenchRayTracing() {}
vtkm::cont::testing::MakeTestDataSet maker;
auto dataset = maker.Make3DUniformDataSet3(dims);
auto coords = dataset.GetCoordinateSystem();
VTKM_CONT BenchRayTracing()
vtkm::rendering::Camera camera;
vtkm::Bounds bounds = dataset.GetCoordinateSystem().GetBounds();
camera.ResetToBounds(bounds);
vtkm::cont::DynamicCellSet cellset = dataset.GetCellSet();
vtkm::rendering::raytracing::TriangleExtractor triExtractor;
triExtractor.ExtractCells(cellset);
auto triIntersector = std::make_shared<vtkm::rendering::raytracing::TriangleIntersector>(
vtkm::rendering::raytracing::TriangleIntersector());
vtkm::rendering::raytracing::RayTracer tracer;
triIntersector->SetData(coords, triExtractor.GetTriangles());
tracer.AddShapeIntersector(triIntersector);
vtkm::rendering::CanvasRayTracer canvas(1920, 1080);
vtkm::rendering::raytracing::Camera rayCamera;
rayCamera.SetParameters(camera, canvas);
vtkm::rendering::raytracing::Ray<vtkm::Float32> rays;
rayCamera.CreateRays(rays, coords.GetBounds());
rays.Buffers.at(0).InitConst(0.f);
vtkm::cont::Field field = dataset.GetField("pointvar");
vtkm::Range range = field.GetRange().ReadPortal().Get(0);
tracer.SetField(field, range);
vtkm::cont::ArrayHandle<vtkm::Vec4ui_8> temp;
vtkm::cont::ColorTable table("cool to warm");
table.Sample(100, temp);
vtkm::cont::ArrayHandle<vtkm::Vec4f_32> colors;
colors.Allocate(100);
auto portal = colors.WritePortal();
auto colorPortal = temp.ReadPortal();
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
for (vtkm::Id i = 0; i < 100; ++i)
{
vtkm::Id3 dims(128, 128, 128);
vtkm::cont::testing::MakeTestDataSet maker;
Data = maker.Make3DUniformDataSet3(dims);
Coords = Data.GetCoordinateSystem();
vtkm::rendering::Camera camera;
vtkm::Bounds bounds = Data.GetCoordinateSystem().GetBounds();
camera.ResetToBounds(bounds);
vtkm::cont::DynamicCellSet cellset = Data.GetCellSet();
vtkm::rendering::raytracing::TriangleExtractor triExtractor;
triExtractor.ExtractCells(cellset);
auto triIntersector = std::make_shared<vtkm::rendering::raytracing::TriangleIntersector>(
vtkm::rendering::raytracing::TriangleIntersector());
triIntersector->SetData(Coords, triExtractor.GetTriangles());
Tracer.AddShapeIntersector(triIntersector);
vtkm::rendering::CanvasRayTracer canvas(1920, 1080);
RayCamera.SetParameters(camera, canvas);
RayCamera.CreateRays(Rays, Coords.GetBounds());
Rays.Buffers.at(0).InitConst(0.f);
vtkm::cont::Field field = Data.GetField("pointvar");
vtkm::Range range = field.GetRange().GetPortalConstControl().Get(0);
Tracer.SetField(field, range);
vtkm::cont::ArrayHandle<vtkm::Vec4ui_8> temp;
vtkm::cont::ColorTable table("cool to warm");
table.Sample(100, temp);
vtkm::cont::ArrayHandle<vtkm::Vec4f_32> colors;
colors.Allocate(100);
auto portal = colors.GetPortalControl();
auto colorPortal = temp.GetPortalConstControl();
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
for (vtkm::Id i = 0; i < 100; ++i)
{
auto color = colorPortal.Get(i);
vtkm::Vec4f_32 t(color[0] * conversionToFloatSpace,
color[1] * conversionToFloatSpace,
color[2] * conversionToFloatSpace,
color[3] * conversionToFloatSpace);
portal.Set(i, t);
}
Tracer.SetColorMap(colors);
Tracer.Render(Rays);
auto color = colorPortal.Get(i);
vtkm::Vec4f_32 t(color[0] * conversionToFloatSpace,
color[1] * conversionToFloatSpace,
color[2] * conversionToFloatSpace,
color[3] * conversionToFloatSpace);
portal.Set(i, t);
}
VTKM_CONT
vtkm::Float64 operator()()
tracer.SetColorMap(colors);
tracer.Render(rays);
vtkm::cont::Timer timer{ Config.Device };
for (auto _ : state)
{
vtkm::cont::Timer timer{ DeviceAdapter() };
(void)_;
timer.Start();
rayCamera.CreateRays(rays, coords.GetBounds());
tracer.Render(rays);
timer.Stop();
RayCamera.CreateRays(Rays, Coords.GetBounds());
try
{
Tracer.Render(Rays);
}
catch (vtkm::cont::ErrorBadValue& e)
{
std::cout << "exception " << e.what() << "\n";
}
return timer.GetElapsedTime();
state.SetIterationTime(timer.GetElapsedTime());
}
VTKM_CONT
std::string Description() const { return "A ray tracing benchmark"; }
};
VTKM_MAKE_BENCHMARK(RayTracing, BenchRayTracing);
}
} // end namespace vtkm::benchmarking
VTKM_BENCHMARK(BenchRayTracing);
} // end namespace vtkm::benchmarking
int main(int argc, char* argv[])
{
auto opts =
vtkm::cont::InitializeOptions::DefaultAnyDevice | vtkm::cont::InitializeOptions::Strict;
auto config = vtkm::cont::Initialize(argc, argv, opts);
// Parse VTK-m options:
auto opts = vtkm::cont::InitializeOptions::RequireDevice | vtkm::cont::InitializeOptions::AddHelp;
Config = vtkm::cont::Initialize(argc, argv, opts);
VTKM_RUN_BENCHMARK(RayTracing, vtkm::ListTagBase<vtkm::Float32>(), config.Device);
return 0;
// Setup device:
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
// handle benchmarking related args and run benchmarks:
VTKM_EXECUTE_BENCHMARKS(argc, argv);
}

@ -7,40 +7,37 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include "Benchmarker.h"
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include "Benchmarker.h"
#include <vtkm/cont/testing/Testing.h>
#include <cctype>
#include <random>
#include <string>
namespace vtkm
{
namespace benchmarking
namespace
{
#define CUBE_SIZE 256
static const std::string DIVIDER(40, '-');
enum BenchmarkName
{
CELL_TO_POINT = 1 << 1,
POINT_TO_CELL = 1 << 2,
MC_CLASSIFY = 1 << 3,
ALL = CELL_TO_POINT | POINT_TO_CELL | MC_CLASSIFY
};
using ValueTypes = vtkm::List<vtkm::UInt32, vtkm::Int32, vtkm::Int64, vtkm::Float32, vtkm::Float64>;
using ValueVariantHandle = vtkm::cont::VariantArrayHandleBase<ValueTypes>;
// Hold configuration state (e.g. active device)
vtkm::cont::InitializeResult Config;
class AveragePointToCell : public vtkm::worklet::WorkletVisitCellsWithPoints
{
@ -118,376 +115,277 @@ public:
}
};
struct ValueTypes
: vtkm::ListTagBase<vtkm::UInt32, vtkm::Int32, vtkm::Int64, vtkm::Float32, vtkm::Float64>
template <typename T, typename Enable = void>
struct NumberGenerator
{
};
/// This class runs a series of micro-benchmarks to measure
/// performance of different field operations
class BenchmarkTopologyAlgorithms
template <typename T>
struct NumberGenerator<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
using StorageTag = vtkm::cont::StorageTagBasic;
using Timer = vtkm::cont::Timer;
using ValueVariantHandle = vtkm::cont::VariantArrayHandleBase<ValueTypes>;
private:
template <typename T, typename Enable = void>
struct NumberGenerator
std::mt19937 rng;
std::uniform_real_distribution<T> distribution;
NumberGenerator(T low, T high)
: rng()
, distribution(low, high)
{
};
}
T next() { return distribution(rng); }
};
template <typename T>
struct NumberGenerator<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
template <typename T>
struct NumberGenerator<T, typename std::enable_if<!std::is_floating_point<T>::value>::type>
{
std::mt19937 rng;
std::uniform_int_distribution<T> distribution;
NumberGenerator(T low, T high)
: rng()
, distribution(low, high)
{
std::mt19937 rng;
std::uniform_real_distribution<T> distribution;
NumberGenerator(T low, T high)
: rng()
, distribution(low, high)
{
}
T next() { return distribution(rng); }
};
}
T next() { return distribution(rng); }
};
template <typename T>
struct NumberGenerator<T, typename std::enable_if<!std::is_floating_point<T>::value>::type>
// Returns an extra random value.
// Like, an additional random value.
// Not a random value that's somehow "extra random".
template <typename ArrayT>
VTKM_CONT typename ArrayT::ValueType FillRandomValues(ArrayT& array,
vtkm::Id size,
vtkm::Float64 min,
vtkm::Float64 max)
{
using ValueType = typename ArrayT::ValueType;
NumberGenerator<ValueType> generator{ static_cast<ValueType>(min), static_cast<ValueType>(max) };
array.Allocate(size);
auto portal = array.WritePortal();
for (vtkm::Id i = 0; i < size; ++i)
{
std::mt19937 rng;
std::uniform_int_distribution<T> distribution;
portal.Set(i, generator.next());
}
return generator.next();
}
NumberGenerator(T low, T high)
: rng()
, distribution(low, high)
{
}
T next() { return distribution(rng); }
};
template <typename Value>
struct BenchCellToPointAvgImpl
{
vtkm::cont::ArrayHandle<Value> Input;
template <typename Value, typename DeviceAdapter>
struct BenchCellToPointAvg
::benchmark::State& State;
vtkm::Id CubeSize;
vtkm::Id NumCells;
vtkm::cont::Timer Timer;
vtkm::cont::Invoker Invoker;
VTKM_CONT
BenchCellToPointAvgImpl(::benchmark::State& state)
: State{ state }
, CubeSize{ CUBE_SIZE }
, NumCells{ (this->CubeSize - 1) * (this->CubeSize - 1) * (this->CubeSize - 1) }
, Timer{ Config.Device }
, Invoker{ Config.Device }
{
std::vector<Value> input;
vtkm::cont::ArrayHandle<Value, StorageTag> InputHandle;
std::size_t DomainSize;
FillRandomValues(this->Input, this->NumCells, 1., 100.);
VTKM_CONT
BenchCellToPointAvg()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0), static_cast<Value>(100.0));
//cube size is points in each dim
this->DomainSize = (CUBE_SIZE - 1) * (CUBE_SIZE - 1) * (CUBE_SIZE - 1);
this->input.resize(DomainSize);
for (std::size_t i = 0; i < DomainSize; ++i)
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
{ // Configure label:
std::ostringstream desc;
desc << "CubeSize:" << this->CubeSize;
this->State.SetLabel(desc.str());
}
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapTopology<AverageCellToPoint> dispatcher;
dispatcher.Invoke(this->InputHandle, cellSet, result);
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const
{
std::stringstream description;
description << "Computing Cell To Point Average "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchCellToPointAvgDynamic : public BenchCellToPointAvg<Value, DeviceAdapter>
template <typename BenchArrayType>
VTKM_CONT void Run(const BenchArrayType& input)
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
vtkm::cont::ArrayHandle<Value> result;
VTKM_CONT
vtkm::Float64 operator()()
for (auto _ : this->State)
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
(void)_;
this->Timer.Start();
this->Invoker(AverageCellToPoint{}, input, cellSet, result);
this->Timer.Stop();
ValueVariantHandle dinput(this->InputHandle);
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapTopology<AverageCellToPoint> dispatcher;
dispatcher.Invoke(dinput, cellSet, result);
return timer.GetElapsedTime();
this->State.SetIterationTime(this->Timer.GetElapsedTime());
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(CellToPointAvg, BenchCellToPointAvg);
VTKM_MAKE_BENCHMARK(CellToPointAvgDynamic, BenchCellToPointAvgDynamic);
template <typename Value, typename DeviceAdapter>
struct BenchPointToCellAvg
{
std::vector<Value> input;
vtkm::cont::ArrayHandle<Value, StorageTag> InputHandle;
std::size_t DomainSize;
VTKM_CONT
BenchPointToCellAvg()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0), static_cast<Value>(100.0));
this->DomainSize = (CUBE_SIZE) * (CUBE_SIZE) * (CUBE_SIZE);
this->input.resize(DomainSize);
for (std::size_t i = 0; i < DomainSize; ++i)
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapTopology<AveragePointToCell> dispatcher;
dispatcher.Invoke(this->InputHandle, cellSet, result);
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const
{
std::stringstream description;
description << "Computing Point To Cell Average "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchPointToCellAvgDynamic : public BenchPointToCellAvg<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
ValueVariantHandle dinput(this->InputHandle);
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapTopology<AveragePointToCell> dispatcher;
dispatcher.Invoke(dinput, cellSet, result);
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(PointToCellAvg, BenchPointToCellAvg);
VTKM_MAKE_BENCHMARK(PointToCellAvgDynamic, BenchPointToCellAvgDynamic);
template <typename Value, typename DeviceAdapter>
struct BenchClassification
{
std::vector<Value> input;
vtkm::cont::ArrayHandle<Value, StorageTag> InputHandle;
Value IsoValue;
size_t DomainSize;
VTKM_CONT
BenchClassification()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0), static_cast<Value>(100.0));
this->DomainSize = (CUBE_SIZE) * (CUBE_SIZE) * (CUBE_SIZE);
this->input.resize(DomainSize);
for (std::size_t i = 0; i < DomainSize; ++i)
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
this->IsoValue = generator.next();
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
vtkm::cont::ArrayHandle<vtkm::IdComponent, StorageTag> result;
ValueVariantHandle dinput(this->InputHandle);
Timer timer{ DeviceAdapter() };
timer.Start();
Classification<Value> worklet(this->IsoValue);
vtkm::worklet::DispatcherMapTopology<Classification<Value>> dispatcher(worklet);
dispatcher.Invoke(dinput, cellSet, result);
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const
{
std::stringstream description;
description << "Computing Marching Cubes Classification "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchClassificationDynamic : public BenchClassification<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE));
vtkm::cont::ArrayHandle<vtkm::IdComponent, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
Classification<Value> worklet(this->IsoValue);
vtkm::worklet::DispatcherMapTopology<Classification<Value>> dispatcher(worklet);
dispatcher.Invoke(this->InputHandle, cellSet, result);
timer.Stop();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(Classification, BenchClassification);
VTKM_MAKE_BENCHMARK(ClassificationDynamic, BenchClassificationDynamic);
public:
static VTKM_CONT int Run(int benchmarks, vtkm::cont::DeviceAdapterId id)
{
std::cout << DIVIDER << "\nRunning Topology Algorithm benchmarks\n";
if (benchmarks & CELL_TO_POINT)
{
std::cout << DIVIDER << "\nBenchmarking Cell To Point Average\n";
VTKM_RUN_BENCHMARK(CellToPointAvg, ValueTypes(), id);
VTKM_RUN_BENCHMARK(CellToPointAvgDynamic, ValueTypes(), id);
}
if (benchmarks & POINT_TO_CELL)
{
std::cout << DIVIDER << "\nBenchmarking Point to Cell Average\n";
VTKM_RUN_BENCHMARK(PointToCellAvg, ValueTypes(), id);
VTKM_RUN_BENCHMARK(PointToCellAvgDynamic, ValueTypes(), id);
}
if (benchmarks & MC_CLASSIFY)
{
std::cout << DIVIDER << "\nBenchmarking Hex/Voxel MC Classification\n";
VTKM_RUN_BENCHMARK(Classification, ValueTypes(), id);
VTKM_RUN_BENCHMARK(ClassificationDynamic, ValueTypes(), id);
}
return 0;
// #items = #points
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfPoints()) * iterations);
}
};
#undef ARRAY_SIZE
}
} // namespace vtkm::benchmarking
template <typename ValueType>
void BenchCellToPointAvgStatic(::benchmark::State& state)
{
BenchCellToPointAvgImpl<ValueType> impl{ state };
impl.Run(impl.Input);
};
VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgStatic, ValueTypes);
template <typename ValueType>
void BenchCellToPointAvgDynamic(::benchmark::State& state)
{
BenchCellToPointAvgImpl<ValueType> impl{ state };
impl.Run(ValueVariantHandle{ impl.Input });
};
VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgDynamic, ValueTypes);
template <typename Value>
struct BenchPointToCellAvgImpl
{
vtkm::cont::ArrayHandle<Value> Input;
::benchmark::State& State;
vtkm::Id CubeSize;
vtkm::Id NumPoints;
vtkm::cont::Timer Timer;
vtkm::cont::Invoker Invoker;
VTKM_CONT
BenchPointToCellAvgImpl(::benchmark::State& state)
: State{ state }
, CubeSize{ CUBE_SIZE }
, NumPoints{ (this->CubeSize) * (this->CubeSize) * (this->CubeSize) }
, Timer{ Config.Device }
, Invoker{ Config.Device }
{
FillRandomValues(this->Input, this->NumPoints, 1., 100.);
{ // Configure label:
std::ostringstream desc;
desc << "CubeSize:" << this->CubeSize;
this->State.SetLabel(desc.str());
}
}
template <typename BenchArrayType>
VTKM_CONT void Run(const BenchArrayType& input)
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
vtkm::cont::ArrayHandle<Value> result;
for (auto _ : this->State)
{
(void)_;
this->Timer.Start();
this->Invoker(AveragePointToCell{}, input, cellSet, result);
this->Timer.Stop();
this->State.SetIterationTime(this->Timer.GetElapsedTime());
}
// #items = #cells
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
}
};
template <typename ValueType>
void BenchPointToCellAvgStatic(::benchmark::State& state)
{
BenchPointToCellAvgImpl<ValueType> impl{ state };
impl.Run(impl.Input);
};
VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgStatic, ValueTypes);
template <typename ValueType>
void BenchPointToCellAvgDynamic(::benchmark::State& state)
{
BenchPointToCellAvgImpl<ValueType> impl{ state };
impl.Run(ValueVariantHandle{ impl.Input });
};
VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgDynamic, ValueTypes);
template <typename Value>
struct BenchClassificationImpl
{
vtkm::cont::ArrayHandle<Value> Input;
::benchmark::State& State;
vtkm::Id CubeSize;
vtkm::Id DomainSize;
Value IsoValue;
vtkm::cont::Timer Timer;
vtkm::cont::Invoker Invoker;
VTKM_CONT
BenchClassificationImpl(::benchmark::State& state)
: State{ state }
, CubeSize{ CUBE_SIZE }
, DomainSize{ this->CubeSize * this->CubeSize * this->CubeSize }
, Timer{ Config.Device }
, Invoker{ Config.Device }
{
this->IsoValue = FillRandomValues(this->Input, this->DomainSize, 1., 100.);
{ // Configure label:
std::ostringstream desc;
desc << "CubeSize:" << this->CubeSize;
this->State.SetLabel(desc.str());
}
}
template <typename BenchArrayType>
VTKM_CONT void Run(const BenchArrayType& input)
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
vtkm::cont::ArrayHandle<vtkm::IdComponent> result;
Classification<Value> worklet(this->IsoValue);
for (auto _ : this->State)
{
(void)_;
this->Timer.Start();
this->Invoker(worklet, input, cellSet, result);
this->Timer.Stop();
this->State.SetIterationTime(this->Timer.GetElapsedTime());
}
// #items = #cells
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
}
};
template <typename ValueType>
void BenchClassificationStatic(::benchmark::State& state)
{
BenchClassificationImpl<ValueType> impl{ state };
impl.Run(impl.Input);
};
VTKM_BENCHMARK_TEMPLATES(BenchClassificationStatic, ValueTypes);
template <typename ValueType>
void BenchClassificationDynamic(::benchmark::State& state)
{
BenchClassificationImpl<ValueType> impl{ state };
impl.Run(ValueVariantHandle{ impl.Input });
};
VTKM_BENCHMARK_TEMPLATES(BenchClassificationDynamic, ValueTypes);
} // end anon namespace
int main(int argc, char* argv[])
{
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
auto config = vtkm::cont::Initialize(argc, argv, opts);
// Parse VTK-m options:
auto opts = vtkm::cont::InitializeOptions::RequireDevice | vtkm::cont::InitializeOptions::AddHelp;
Config = vtkm::cont::Initialize(argc, argv, opts);
int benchmarks = 0;
if (argc <= 1)
{
benchmarks = vtkm::benchmarking::ALL;
}
else
{
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
std::transform(arg.begin(), arg.end(), arg.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
if (arg == "celltopoint")
{
benchmarks |= vtkm::benchmarking::CELL_TO_POINT;
}
else if (arg == "pointtocell")
{
benchmarks |= vtkm::benchmarking::POINT_TO_CELL;
}
else if (arg == "classify")
{
benchmarks |= vtkm::benchmarking::MC_CLASSIFY;
}
else
{
std::cerr << "Unrecognized benchmark: " << argv[i] << std::endl;
std::cerr << "USAGE: " << argv[0] << " [options] [<benchmarks>]" << std::endl;
std::cerr << "Options are: " << std::endl;
std::cerr << config.Usage << std::endl;
std::cerr << "Benchmarks are one or more of the following:" << std::endl;
std::cerr << " CellToPoint\tFind average of point data on each cell" << std::endl;
std::cerr << " PointToCell\tFind average of cell data on each point" << std::endl;
std::cerr << " Classify\tFind Marching Cube case of each cell" << std::endl;
std::cerr << "If no benchmarks are specified, all are run." << std::endl;
return 1;
}
}
}
// Setup device:
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
//now actually execute the benchmarks
return vtkm::benchmarking::BenchmarkTopologyAlgorithms::Run(benchmarks, config.Device);
// handle benchmarking related args and run benchmarks:
VTKM_EXECUTE_BENCHMARKS(argc, argv);
}

@ -11,331 +11,385 @@
#ifndef vtk_m_benchmarking_Benchmarker_h
#define vtk_m_benchmarking_Benchmarker_h
#include <vtkm/ListTag.h>
#include <vtkm/Math.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/testing/Testing.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <vtkm/internal/brigand.hpp>
/*
* Writing a Benchmark
* -------------------
* To write a benchmark you must provide a functor that will run the operations
* you want to time and return the run time of those operations using the timer
* for the device. The benchmark should also be templated on the value type being
* operated on. Then use VTKM_MAKE_BENCHMARK to generate a maker functor and
* VTKM_RUN_BENCHMARK to run the benchmark on a list of types.
*
* For Example:
*
* template<typename Value>
* struct BenchSilly {
* // Setup anything that doesn't need to change per run in the constructor
* VTKM_CONT BenchSilly(){}
*
* // The overloaded call operator will run the operations being timed and
* // return the execution time
* VTKM_CONT
* vtkm::Float64 operator()(){
* return 0.05;
* }
*
* // The benchmark must also provide a method describing itself, this is
* // used when printing out run time statistics
* VTKM_CONT
* std::string Description() const {
* return "A silly benchmark";
* }
* };
*
* // Now use the VTKM_MAKE_BENCHMARK macro to generate a maker functor for
* // your benchmark. This lets us generate the benchmark functor for each type
* // we want to test
* VTKM_MAKE_BENCHMARK(Silly, BenchSilly);
*
* // You can also optionally pass arguments to the constructor like so:
* // VTKM_MAKE_BENCHMARK(Blah, BenchBlah, 1, 2, 3);
* // Note that benchmark names (the first argument) must be unique so different
* // parameters to the constructor should have different names
*
* // We can now run our benchmark using VTKM_RUN_BENCHMARK, passing the
* // benchmark name and type list to run on
* int main(int, char**){
* VTKM_RUN_BENCHMARK(Silly, vtkm::ListTagBase<vtkm::Float32>());
* return 0;
* }
*
* Check out vtkm/benchmarking/BenchmarkDeviceAdapter.h for some example usage
*/
#include <benchmark/benchmark.h>
/*
* Use the VTKM_MAKE_BENCHMARK macro to define a maker functor for your benchmark.
* This is used to allow you to template the benchmark functor on the type being benchmarked
* and the device adapter so you can write init code in the constructor. Then the maker will
* return a constructed instance of your benchmark for the type being benchmarked.
* The VA_ARGS are used to pass any extra arguments needed by your benchmark
*/
#define VTKM_MAKE_BENCHMARK(Name, Bench, ...) \
struct MakeBench##Name \
{ \
template <typename Value, typename DeviceAdapter> \
VTKM_CONT Bench<Value, DeviceAdapter> operator()(const Value vtkmNotUsed(v), \
DeviceAdapter vtkmNotUsed(id)) const \
{ \
return Bench<Value, DeviceAdapter>(__VA_ARGS__); \
} \
}
#include <ostream>
/*
* Use the VTKM_RUN_BENCHMARK macro to run your benchmark on the type list passed.
* You must have previously defined a maker functor with VTKM_MAKE_BENCHMARK that this
* macro will look for and use
*/
#define VTKM_RUN_BENCHMARK(Name, Types, Id) \
vtkm::benchmarking::BenchmarkTypes(MakeBench##Name(), (Types), (Id))
/// \file Benchmarker.h
/// \brief Benchmarking utilities
///
/// VTK-m's benchmarking framework is built on top of Google Benchmark.
///
/// A benchmark is now a single function, which is passed to a macro:
///
/// ```
/// void MyBenchmark(::benchmark::State& state)
/// {
/// MyClass someClass;
///
/// // Optional: Add a descriptive label with additional benchmark details:
/// state.SetLabel("Blah blah blah.");
///
/// // Must use a vtkm timer to properly capture eg. CUDA execution times.
/// vtkm::cont::Timer timer;
/// for (auto _ : state)
/// {
/// someClass.Reset();
///
/// timer.Start();
/// someClass.DoWork();
/// timer.Stop();
///
/// state.SetIterationTime(timer.GetElapsedTime());
/// }
///
/// // Optional: Report items and/or bytes processed per iteration in output:
/// state.SetItemsProcessed(state.iterations() * someClass.GetNumberOfItems());
/// state.SetBytesProcessed(state.iterations() * someClass.GetNumberOfBytes());
/// }
/// }
/// VTKM_BENCHMARK(MyBenchmark);
/// ```
///
/// Google benchmark also makes it easy to implement parameter sweep benchmarks:
///
/// ```
/// void MyParameterSweep(::benchmark::State& state)
/// {
/// // The current value in the sweep:
/// const vtkm::Id currentValue = state.range(0);
///
/// MyClass someClass;
/// someClass.SetSomeParameter(currentValue);
///
/// vtkm::cont::Timer timer;
/// for (auto _ : state)
/// {
/// someClass.Reset();
///
/// timer.Start();
/// someClass.DoWork();
/// timer.Stop();
///
/// state.SetIterationTime(timer.GetElapsedTime());
/// }
/// }
/// VTKM_BENCHMARK_OPTS(MyBenchmark, ->ArgName("Param")->Range(32, 1024 * 1024));
/// ```
///
/// will generate and launch several benchmarks, exploring the parameter space of
/// `SetSomeParameter` between the values of 32 and (1024*1024). The chain of
/// functions calls in the second argument is applied to an instance of
/// ::benchmark::internal::Benchmark. See Google Benchmark's documentation for
/// more details.
///
/// For more complex benchmark configurations, the VTKM_BENCHMARK_APPLY macro
/// accepts a function with the signature
/// `void Func(::benchmark::internal::Benchmark*)` that may be used to generate
/// more complex configurations.
///
/// To instantiate a templated benchmark across a list of types, the
/// VTKM_BENCHMARK_TEMPLATE* macros take a vtkm::List of types as an additional
/// parameter. The templated benchmark function will be instantiated and called
/// for each type in the list:
///
/// ```
/// template <typename T>
/// void MyBenchmark(::benchmark::State& state)
/// {
/// MyClass<T> someClass;
///
/// // Must use a vtkm timer to properly capture eg. CUDA execution times.
/// vtkm::cont::Timer timer;
/// for (auto _ : state)
/// {
/// someClass.Reset();
///
/// timer.Start();
/// someClass.DoWork();
/// timer.Stop();
///
/// state.SetIterationTime(timer.GetElapsedTime());
/// }
/// }
/// }
/// VTKM_BENCHMARK_TEMPLATE(MyBenchmark, vtkm::List<vtkm::Float32, vtkm::Vec3f_32>);
/// ```
///
/// The benchmarks are executed by calling the `VTKM_EXECUTE_BENCHMARKS(argc, argv)`
/// macro from `main`. There is also a `VTKM_EXECUTE_BENCHMARKS_PREAMBLE(argc, argv, some_string)`
/// macro that appends the contents of `some_string` to the Google Benchmark preamble.
///
/// If a benchmark is not compatible with some configuration, it may call
/// `state.SkipWithError("Error message");` on the `::benchmark::State` object and return. This is
/// useful, for instance in the filter tests when the input is not compatible with the filter.
///
/// When launching a benchmark executable, the following options are supported by Google Benchmark:
///
/// - `--benchmark_list_tests`: List all available tests.
/// - `--benchmark_filter="[regex]"`: Only run benchmark with names that match `[regex]`.
/// - `--benchmark_filter="-[regex]"`: Only run benchmark with names that DON'T match `[regex]`.
/// - `--benchmark_min_time=[float]`: Make sure each benchmark repetition gathers `[float]` seconds
/// of data.
/// - `--benchmark_repetitions=[int]`: Run each benchmark `[int]` times and report aggregate statistics
/// (mean, stdev, etc). A "repetition" refers to a single execution of the benchmark function, not
/// an "iteration", which is a loop of the `for(auto _:state){...}` section.
/// - `--benchmark_report_aggregates_only="true|false"`: If true, only the aggregate statistics are
/// reported (affects both console and file output). Requires `--benchmark_repetitions` to be useful.
/// - `--benchmark_display_aggregates_only="true|false"`: If true, only the aggregate statistics are
/// printed to the terminal. Any file output will still contain all repetition info.
/// - `--benchmark_format="console|json|csv"`: Specify terminal output format: human readable
/// (`console`) or `csv`/`json` formats.
/// - `--benchmark_out_format="console|json|csv"`: Specify file output format: human readable
/// (`console`) or `csv`/`json` formats.
/// - `--benchmark_out=[filename]`: Specify output file.
/// - `--benchmark_color="true|false"`: Toggle color output in terminal when using `console` output.
/// - `--benchmark_counters_tabular="true|false"`: Print counter information (e.g. bytes/sec, items/sec)
/// in the table, rather than appending them as a label.
///
/// For more information and examples of practical usage, take a look at the existing benchmarks in
/// vtk-m/benchmarking/.
/// \def VTKM_EXECUTE_BENCHMARKS(argc, argv)
///
/// Run the benchmarks defined in the current file. Benchmarks may be filtered
/// and modified using the passed arguments; see the Google Benchmark documentation
/// for more details.
#define VTKM_EXECUTE_BENCHMARKS(argc, argv) vtkm::bench::detail::ExecuteBenchmarks(argc, argv)
/// \def VTKM_EXECUTE_BENCHMARKS_PREAMBLE(argc, argv, preamble)
///
/// Run the benchmarks defined in the current file. Benchmarks may be filtered
/// and modified using the passed arguments; see the Google Benchmark documentation
/// for more details. The `preamble` string may be used to supply additional
/// information that will be appended to the output's preamble.
#define VTKM_EXECUTE_BENCHMARKS_PREAMBLE(argc, argv, preamble) \
vtkm::bench::detail::ExecuteBenchmarks(argc, argv, preamble)
/// \def VTKM_BENCHMARK(BenchFunc)
///
/// Define a simple benchmark. A single benchmark will be generated that executes
/// `BenchFunc`. `BenchFunc` must have the signature:
///
/// ```
/// void BenchFunc(::benchmark::State& state)
/// ```
#define VTKM_BENCHMARK(BenchFunc) BENCHMARK(BenchFunc)->UseManualTime()
/// \def VTKM_BENCHMARK_OPTS(BenchFunc, Args)
///
/// Similar to `VTKM_BENCHMARK`, but allows additional options to be specified
/// on the `::benchmark::internal::Benchmark` object. Example usage:
///
/// ```
/// VTKM_BENCHMARK_OPTS(MyBenchmark, ->ArgName("MyParam")->Range(32, 1024*1024));
/// ```
///
/// Note the similarity to the raw Google Benchmark usage of
/// `BENCHMARK(MyBenchmark)->ArgName("MyParam")->Range(32, 1024*1024);`. See
/// the Google Benchmark documentation for more details on the available options.
#define VTKM_BENCHMARK_OPTS(BenchFunc, options) BENCHMARK(BenchFunc)->UseManualTime() options
/// \def VTKM_BENCHMARK_APPLY(BenchFunc, ConfigFunc)
///
/// Similar to `VTKM_BENCHMARK`, but allows advanced benchmark configuration
/// via a supplied ConfigFunc, similar to Google Benchmark's
/// `BENCHMARK(BenchFunc)->Apply(ConfigFunc)`. `ConfigFunc` must have the
/// signature:
///
/// ```
/// void ConfigFunc(::benchmark::internal::Benchmark*);
/// ```
///
/// See the Google Benchmark documentation for more details on the available options.
#define VTKM_BENCHMARK_APPLY(BenchFunc, applyFunctor) \
BENCHMARK(BenchFunc)->Apply(applyFunctor)->UseManualTime()
/// \def VTKM_BENCHMARK_TEMPLATES(BenchFunc, TypeList)
///
/// Define a family of benchmark that vary by template argument. A single
/// benchmark will be generated for each type in `TypeList` (a vtkm::List of
/// types) that executes `BenchFunc<T>`. `BenchFunc` must have the signature:
///
/// ```
/// template <typename T>
/// void BenchFunc(::benchmark::State& state)
/// ```
#define VTKM_BENCHMARK_TEMPLATES(BenchFunc, TypeList) \
VTKM_BENCHMARK_TEMPLATES_APPLY(BenchFunc, vtkm::bench::detail::NullApply, TypeList)
/// \def VTKM_BENCHMARK_TEMPLATES_OPTS(BenchFunc, Args, TypeList)
///
/// Similar to `VTKM_BENCHMARK_TEMPLATES`, but allows additional options to be specified
/// on the `::benchmark::internal::Benchmark` object. Example usage:
///
/// ```
/// VTKM_BENCHMARK_TEMPLATES_OPTS(MyBenchmark,
/// ->ArgName("MyParam")->Range(32, 1024*1024),
/// vtkm::List<vtkm::Float32, vtkm::Vec3f_32>);
/// ```
#define VTKM_BENCHMARK_TEMPLATES_OPTS(BenchFunc, options, TypeList) \
VTKM_BENCHMARK_TEMPLATES_APPLY( \
BenchFunc, [](::benchmark::internal::Benchmark* bm) { bm options; }, TypeList)
/// \def VTKM_BENCHMARK_TEMPLATES_APPLY(BenchFunc, ConfigFunc, TypeList)
///
/// Similar to `VTKM_BENCHMARK_TEMPLATES`, but allows advanced benchmark configuration
/// via a supplied ConfigFunc, similar to Google Benchmark's
/// `BENCHMARK(BenchFunc)->Apply(ConfigFunc)`. `ConfigFunc` must have the
/// signature:
///
/// ```
/// void ConfigFunc(::benchmark::internal::Benchmark*);
/// ```
///
/// See the Google Benchmark documentation for more details on the available options.
#define VTKM_BENCHMARK_TEMPLATES_APPLY(BenchFunc, ApplyFunctor, TypeList) \
namespace \
{ /* A template function cannot be used as a template parameter, so wrap the function with \
* a template struct to get it into the GenerateTemplateBenchmarks class. */ \
template <typename... Ts> \
struct VTKM_BENCHMARK_WRAPPER_NAME(BenchFunc) \
{ \
static ::benchmark::internal::Function* GetFunction() { return BenchFunc<Ts...>; } \
}; \
} /* end anon namespace */ \
int BENCHMARK_PRIVATE_NAME(BenchFunc) = vtkm::bench::detail::GenerateTemplateBenchmarks< \
brigand::bind<VTKM_BENCHMARK_WRAPPER_NAME(BenchFunc)>, \
TypeList>::Register(#BenchFunc, ApplyFunctor)
// Internal use only:
#define VTKM_BENCHMARK_WRAPPER_NAME(BenchFunc) \
BENCHMARK_PRIVATE_CONCAT(_wrapper_, BenchFunc, __LINE__)
namespace vtkm
{
namespace benchmarking
namespace bench
{
namespace stats
namespace detail
{
// Checks that the sequence is sorted, returns true if it's sorted, false
// otherwise
template <typename ForwardIt>
bool is_sorted(ForwardIt first, ForwardIt last)
static inline void NullApply(::benchmark::internal::Benchmark*)
{
ForwardIt next = first;
++next;
for (; next != last; ++next, ++first)
}
/// Do not use directly. The VTKM_BENCHMARK_TEMPLATES macros should be used
/// instead.
// TypeLists could be expanded to compute cross products if we ever have that
// need.
template <typename BoundBench, typename TypeLists>
struct GenerateTemplateBenchmarks;
template <template <typename...> class BenchType, typename TypeList>
struct GenerateTemplateBenchmarks<brigand::bind<BenchType>, TypeList>
{
private:
template <typename T>
using MakeBenchType = BenchType<T>;
using Benchmarks = brigand::transform<TypeList, brigand::bind<MakeBenchType, brigand::_1>>;
template <typename ApplyFunctor>
struct RegisterImpl
{
if (*first > *next)
std::string BenchName;
ApplyFunctor Apply;
template <typename P>
void operator()(brigand::type_<BenchType<P>>) const
{
std::ostringstream name;
name << this->BenchName << "<" << vtkm::testing::TypeName<P>::Name() << ">";
auto bm = ::benchmark::internal::RegisterBenchmarkInternal(
new ::benchmark::internal::FunctionBenchmark(name.str().c_str(),
BenchType<P>::GetFunction()));
this->Apply(bm);
// Always use manual time with vtkm::cont::Timer to capture CUDA times accurately.
bm->UseManualTime();
}
};
public:
template <typename ApplyFunctor>
static int Register(const std::string& benchName, ApplyFunctor&& apply)
{
brigand::for_each<Benchmarks>(
RegisterImpl<ApplyFunctor>{ benchName, std::forward<ApplyFunctor>(apply) });
return 0;
}
};
class VTKmConsoleReporter : public ::benchmark::ConsoleReporter
{
std::string UserPreamble;
public:
VTKmConsoleReporter() = default;
explicit VTKmConsoleReporter(const std::string& preamble)
: UserPreamble{ preamble }
{
}
bool ReportContext(const Context& context) override
{
if (!::benchmark::ConsoleReporter::ReportContext(context))
{
return false;
}
}
return true;
}
// Get the value representing the `percent` percentile of the
// sorted samples using linear interpolation
vtkm::Float64 PercentileValue(const std::vector<vtkm::Float64>& samples,
const vtkm::Float64 percent)
{
VTKM_ASSERT(!samples.empty());
if (samples.size() == 1)
{
return samples.front();
}
VTKM_ASSERT(percent >= 0.0);
VTKM_ASSERT(percent <= 100.0);
VTKM_ASSERT(vtkm::benchmarking::stats::is_sorted(samples.begin(), samples.end()));
if (percent == 100.0)
{
return samples.back();
}
// Find the two nearest percentile values and linearly
// interpolate between them
const vtkm::Float64 rank = percent / 100.0 * (static_cast<vtkm::Float64>(samples.size()) - 1.0);
const vtkm::Float64 low_rank = vtkm::Floor(rank);
const vtkm::Float64 dist = rank - low_rank;
const size_t k = static_cast<size_t>(low_rank);
const vtkm::Float64 low = samples[k];
const vtkm::Float64 high = samples[k + 1];
return low + (high - low) * dist;
}
// Winsorize the samples to clean up any very extreme outliers
// Will replace all samples below `percent` and above 100 - `percent` percentiles
// with the value at the percentile
// NOTE: Assumes the samples have been sorted, as we make use of PercentileValue
void Winsorize(std::vector<vtkm::Float64>& samples, const vtkm::Float64 percent)
{
const vtkm::Float64 low_percentile = PercentileValue(samples, percent);
const vtkm::Float64 high_percentile = PercentileValue(samples, 100.0 - percent);
for (std::vector<vtkm::Float64>::iterator it = samples.begin(); it != samples.end(); ++it)
{
if (*it < low_percentile)
// The rest of the preamble is printed to the error stream, so be consistent:
auto& out = this->GetErrorStream();
// Print list of devices:
out << "VTK-m Device State:\n";
vtkm::cont::GetRuntimeDeviceTracker().PrintSummary(out);
if (!this->UserPreamble.empty())
{
*it = low_percentile;
out << this->UserPreamble << "\n";
}
else if (*it > high_percentile)
{
*it = high_percentile;
}
}
}
// Compute the mean value of the dataset
vtkm::Float64 Mean(const std::vector<vtkm::Float64>& samples)
{
vtkm::Float64 mean = 0;
for (std::vector<vtkm::Float64>::const_iterator it = samples.begin(); it != samples.end(); ++it)
{
mean += *it;
}
return mean / static_cast<vtkm::Float64>(samples.size());
}
// Compute the sample variance of the samples
vtkm::Float64 Variance(const std::vector<vtkm::Float64>& samples)
{
vtkm::Float64 mean = Mean(samples);
vtkm::Float64 square_deviations = 0;
for (std::vector<vtkm::Float64>::const_iterator it = samples.begin(); it != samples.end(); ++it)
{
square_deviations += vtkm::Pow(*it - mean, 2.0);
}
return square_deviations / (static_cast<vtkm::Float64>(samples.size()) - 1.0);
}
// Compute the standard deviation of the samples
vtkm::Float64 StandardDeviation(const std::vector<vtkm::Float64>& samples)
{
return vtkm::Sqrt(Variance(samples));
}
// Compute the median absolute deviation of the dataset
vtkm::Float64 MedianAbsDeviation(const std::vector<vtkm::Float64>& samples)
{
std::vector<vtkm::Float64> abs_deviations;
abs_deviations.reserve(samples.size());
const vtkm::Float64 median = PercentileValue(samples, 50.0);
for (std::vector<vtkm::Float64>::const_iterator it = samples.begin(); it != samples.end(); ++it)
{
abs_deviations.push_back(vtkm::Abs(*it - median));
}
std::sort(abs_deviations.begin(), abs_deviations.end());
return PercentileValue(abs_deviations, 50.0);
}
} // stats
out.flush();
/*
* The benchmarker takes a functor to benchmark and runs it multiple times,
* printing out statistics of the run time at the end.
* The functor passed should return the run time of the thing being benchmarked
* in seconds, this lets us avoid including any per-run setup time in the benchmark.
* However any one-time setup should be done in the functor's constructor
*/
struct Benchmarker
{
std::vector<vtkm::Float64> Samples;
std::string BenchmarkName;
const vtkm::Float64 MaxRuntime;
const size_t MaxIterations;
public:
VTKM_CONT
Benchmarker(vtkm::Float64 maxRuntime = 30, std::size_t maxIterations = 100)
: MaxRuntime(maxRuntime)
, MaxIterations(maxIterations)
{
}
template <typename Functor>
VTKM_CONT void GatherSamples(Functor func)
{
this->Samples.clear();
this->BenchmarkName = func.Description();
// Do a warm-up run. If the benchmark allocates any additional memory
// eg. storage for output results, this will let it do that and
// allow us to avoid measuring the allocation time in the actual benchmark run
func();
this->Samples.reserve(this->MaxIterations);
// Run each benchmark for MAX_RUNTIME seconds or MAX_ITERATIONS iterations, whichever
// takes less time. This kind of assumes that running for 500 iterations or 30s will give
// good statistics, but if median abs dev and/or std dev are too high both these limits
// could be increased
size_t iter = 0;
for (vtkm::Float64 elapsed = 0.0; elapsed < this->MaxRuntime && iter < this->MaxIterations;
elapsed += this->Samples.back(), ++iter)
{
this->Samples.push_back(func());
}
std::sort(this->Samples.begin(), this->Samples.end());
stats::Winsorize(this->Samples, 5.0);
}
VTKM_CONT void PrintSummary(std::ostream& out = std::cout)
{
out << "Benchmark \'" << this->BenchmarkName << "\' results:\n";
if (this->Samples.empty())
{
out << "\tNo samples gathered!\n";
return;
}
out << "\tnumSamples = " << this->Samples.size() << "\n"
<< "\tmedian = " << stats::PercentileValue(this->Samples, 50.0) << "s\n"
<< "\tmedian abs dev = " << stats::MedianAbsDeviation(this->Samples) << "s\n"
<< "\tmean = " << stats::Mean(this->Samples) << "s\n"
<< "\tstd dev = " << stats::StandardDeviation(this->Samples) << "s\n"
<< "\tmin = " << this->Samples.front() << "s\n"
<< "\tmax = " << this->Samples.back() << "s\n";
}
template <typename DeviceAdapter, typename MakerFunctor, typename T>
VTKM_CONT bool operator()(DeviceAdapter id, MakerFunctor&& makerFunctor, T t)
{
auto func = makerFunctor(t, id);
std::cout << "Running '" << func.Description() << "'" << std::endl;
this->GatherSamples(func);
this->PrintSummary();
return true;
}
VTKM_CONT const std::vector<vtkm::Float64>& GetSamples() const { return this->Samples; }
VTKM_CONT void Reset()
{
this->Samples.clear();
this->BenchmarkName.clear();
}
};
template <typename MakerFunctor>
class InternalPrintTypeAndBench
// Returns the number of executed benchmarks:
static inline vtkm::Id ExecuteBenchmarks(int& argc,
char* argv[],
const std::string& preamble = std::string{})
{
MakerFunctor Maker;
public:
VTKM_CONT
InternalPrintTypeAndBench(MakerFunctor maker)
: Maker(maker)
::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
{
return 1;
}
template <typename T>
VTKM_CONT void operator()(T t, vtkm::cont::DeviceAdapterId id) const
{
std::cout << "*** " << vtkm::testing::TypeName<T>::Name() << " on device " << id.GetName()
<< " ***************" << std::endl;
Benchmarker bench;
try
{
vtkm::cont::TryExecuteOnDevice(id, bench, Maker, t);
}
catch (std::exception& e)
{
std::cout << "\n"
<< "An exception occurring during a benchmark:\n\t" << e.what() << "\n"
<< "Attempting to continue with remaining benchmarks...\n\n";
}
}
};
VTKmConsoleReporter reporter{ preamble };
template <class MakerFunctor, class TypeList>
VTKM_CONT void BenchmarkTypes(MakerFunctor&& maker, TypeList, vtkm::cont::DeviceAdapterId id)
{
vtkm::ListForEach(
InternalPrintTypeAndBench<MakerFunctor>(std::forward<MakerFunctor>(maker)), TypeList(), id);
vtkm::cont::Timer timer;
timer.Start();
std::size_t num = ::benchmark::RunSpecifiedBenchmarks(&reporter);
timer.Stop();
reporter.GetOutputStream().flush();
reporter.GetErrorStream().flush();
reporter.GetErrorStream() << "Ran " << num << " benchmarks in " << timer.GetElapsedTime()
<< " seconds." << std::endl;
return static_cast<vtkm::Id>(num);
}
}
}
} // end namespace vtkm::bench::detail
#endif

@ -7,18 +7,24 @@
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
##============================================================================
# Find Google Benchmark. Note that benchmark_DIR must be pointed at an
# installation, not a build directory.
find_package(benchmark REQUIRED)
function(add_benchmark)
set(options)
set(oneValueArgs NAME FILE)
set(multiValueArgs LIBS)
cmake_parse_arguments(VTKm_AB
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
set(exe_name ${VTKm_AB_NAME})
add_executable(${exe_name} ${VTKm_AB_FILE})
target_link_libraries(${exe_name} PRIVATE ${VTKm_AB_LIBS})
target_link_libraries(${exe_name} PRIVATE benchmark::benchmark)
vtkm_add_drop_unused_function_flags(${exe_name})
vtkm_add_target_information(${exe_name})

24
docs/CODEOWNERS Normal file

@ -0,0 +1,24 @@
# Subsystems have specific owners
CMake/ @robertmaynard
data/ @dpugmire
docs/ @robertmaynard @kmorel
examples/ @kmorel
Utilities/ @kmorel
vtkm/ @robertmaynard @kmorel
vtkm/interop/ @robertmaynard
vtkm/io/ @sujin.philip
vtkm/rendering/ @mclarsen
vtkm/source/ @robertmaynard @ollielo
vtkm/testing/ @sujin.philip
vtkm/thirdparty/ @ben.boeckel
vtkm/worklet/cellmetrics/ @hankchilds
vtkm/worklet/contourtree/ @oruebel @ghweber @sujin.philip
vtkm/worklet/contourtree_augmented/ @oruebel @ghweber @sujin.philip
vtkm/worklet/cosmotools/ @ollielo
vtkm/worklet/lcs/ @ayenpure @dpugmire
vtkm/worklet/moments/ @ollielo @robertmaynard
vtkm/worklet/particleadvection @ayenpure @dpugmire
vtkm/worklet/spatialstructure @ayenpure @kmorel
vtkm/worklet/zfp @mclarsen

@ -0,0 +1,24 @@
# `ArrayHandleGroupVecVariable` holds now one more offset.
This change affects the usage of both `ConvertNumComponentsToOffsets` and
`make_ArrayHandleGroupVecVariable`.
The reason of this change is to remove a branch in
`ArrayHandleGroupVecVariable::Get` which is used to avoid an array overflow,
this in theory would increases the performance since at the CPU level it will
remove penalties due to wrong branch predictions.
The change affects `ConvertNumComponentsToOffsets` by both:
1. Increasing the numbers of elements in `offsetsArray` (its second parameter)
by one.
2. Setting `sourceArraySize` as the sum of all the elements plus the new one
in `offsetsArray`
Note that not every specialization of `ConvertNumComponentsToOffsets` does
return `offsetsArray`. Thus, some of them would not be affected.
Similarly, this change affects `make_ArrayHandleGroupVecVariable` since it
expects its second parameter (offsetsArray) to be one element bigger than
before.

@ -0,0 +1,72 @@
# Algorithms for Control and Execution Environments
The `<vtkm/Algorithms.h>` header has been added to provide common STL-style
generic algorithms that are suitable for use in both the control and execution
environments. This is necessary as the STL algorithms in the `<algorithm>`
header are not marked up for use in execution environments such as CUDA.
In addition to the markup, these algorithms have convenience overloads to
support ArrayPortals directly, simplifying their usage with VTK-m data
structures.
Currently, three related algorithms are provided: `LowerBounds`, `UpperBounds`,
and `BinarySearch`. `BinarySearch` differs from the STL `std::binary_search`
algorithm in that it returns an iterator (or index) to a matching element,
rather than just a boolean indicating whether a or not key is present.
The new algorithm signatures are:
```c++
namespace vtkm
{
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT
IterT BinarySearch(IterT first, IterT last, const T& val, Comp comp);
template <typename IterT, typename T>
VTKM_EXEC_CONT
IterT BinarySearch(IterT first, IterT last, const T& val);
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT
vtkm::Id BinarySearch(const PortalT& portal, const T& val, Comp comp);
template <typename PortalT, typename T>
VTKM_EXEC_CONT
vtkm::Id BinarySearch(const PortalT& portal, const T& val);
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT
IterT LowerBound(IterT first, IterT last, const T& val, Comp comp);
template <typename IterT, typename T>
VTKM_EXEC_CONT
IterT LowerBound(IterT first, IterT last, const T& val);
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT
vtkm::Id LowerBound(const PortalT& portal, const T& val, Comp comp);
template <typename PortalT, typename T>
VTKM_EXEC_CONT
vtkm::Id LowerBound(const PortalT& portal, const T& val);
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT
IterT UpperBound(IterT first, IterT last, const T& val, Comp comp);
template <typename IterT, typename T>
VTKM_EXEC_CONT
IterT UpperBound(IterT first, IterT last, const T& val);
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT
vtkm::Id UpperBound(const PortalT& portal, const T& val, Comp comp);
template <typename PortalT, typename T>
VTKM_EXEC_CONT
vtkm::Id UpperBound(const PortalT& portal, const T& val);
}
```

@ -0,0 +1,28 @@
# Portals may advertise custom iterators
The `ArrayPortalToIterator` utilities are used to produce STL-style iterators
from vtk-m's `ArrayHandle` portals. By default, a facade class is constructed
around the portal API, adapting it to an iterator interface.
However, some portals use iterators internally, or may be able to construct a
lightweight iterator easily. For these, it is preferable to directly use the
specialized iterators instead of going through the generic facade. A portal may
now declare the following optional API to advertise that it has custom
iterators:
```
struct MyPortal
{
using IteratorType = ...; // alias to the portal's specialized iterator type
IteratorType GetIteratorBegin(); // Return the begin iterator
IteratorType GetIteratorEnd(); // Return the end iterator
// ...rest of ArrayPortal API...
};
```
If these members are present, `ArrayPortalToIterators` will forward the portal's
specialized iterators instead of constructing a facade. This works when using
the `ArrayPortalToIterators` class directly, and also with the
`ArrayPortalToIteratorBegin` and `ArrayPortalToIteratorEnd` convenience
functions.

@ -0,0 +1,114 @@
# ArrayHandleDecorator Allocate and Shrink Support
`ArrayHandleDecorator` can now be resized when given an appropriate
decorator implementation.
Since the mapping between the size of an `ArrayHandleDecorator` and its source
`ArrayHandle`s is not well defined, resize operations (such as `Shrink` and
`Allocate`) are not defined by default, and will throw an exception if called.
However, by implementing the methods `AllocateSourceArrays` and/or
`ShrinkSourceArrays` on the implementation class, resizing the decorator is
allowed. These methods are passed in a new size along with each of the
`ArrayHandleDecorator`'s source arrays, allowing developers to control how
the resize operation should affect the source arrays.
For example, the following decorator implementation can be used to create a
resizable `ArrayHandleDecorator` that is implemented using two arrays, which
are combined to produce values via the expression:
```
[decorator value i] = [source1 value i] * 10 + [source2 value i]
```
Implementation:
```c++
template <typename ValueType>
struct DecompositionDecorImpl
{
template <typename Portal1T, typename Portal2T>
struct Functor
{
Portal1T Portal1;
Portal2T Portal2;
VTKM_EXEC_CONT
ValueType operator()(vtkm::Id idx) const
{
return static_cast<ValueType>(this->Portal1.Get(idx) * 10 + this->Portal2.Get(idx));
}
};
template <typename Portal1T, typename Portal2T>
struct InverseFunctor
{
Portal1T Portal1;
Portal2T Portal2;
VTKM_EXEC_CONT
void operator()(vtkm::Id idx, const ValueType& val) const
{
this->Portal1.Set(idx, static_cast<ValueType>(std::floor(val / 10)));
this->Portal2.Set(idx, static_cast<ValueType>(std::fmod(val, 10)));
}
};
template <typename Portal1T, typename Portal2T>
VTKM_CONT Functor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
CreateFunctor(Portal1T&& p1, Portal2T&& p2) const
{
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
}
template <typename Portal1T, typename Portal2T>
VTKM_CONT InverseFunctor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
CreateInverseFunctor(Portal1T&& p1, Portal2T&& p2) const
{
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
}
// Resize methods:
template <typename Array1T, typename Array2T>
VTKM_CONT
void AllocateSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
{
array1.Allocate(numVals);
array2.Allocate(numVals);
}
template <typename Array1T, typename Array2T>
VTKM_CONT
void ShrinkSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
{
array1.Shrink(numVals);
array2.Shrink(numVals);
}
};
// Usage:
vtkm::cont::ArrayHandle<ValueType> a1;
vtkm::cont::ArrayHandle<ValueType> a2;
auto decor = vtkm::cont::make_ArrayHandleDecorator(0, DecompositionDecorImpl<ValueType>{}, a1, a2);
decor.Allocate(5);
{
auto decorPortal = decor.GetPortalControl();
decorPortal.Set(0, 13);
decorPortal.Set(1, 8);
decorPortal.Set(2, 43);
decorPortal.Set(3, 92);
decorPortal.Set(4, 117);
}
// a1: { 1, 0, 4, 9, 11 }
// a2: { 3, 8, 3, 2, 7 }
// decor: { 13, 8, 43, 92, 117 }
decor.Shrink(3);
// a1: { 1, 0, 4 }
// a2: { 3, 8, 3 }
// decor: { 13, 8, 43 }
```

@ -0,0 +1,97 @@
# Add VTKM_DEPRECATED macro
The `VTKM_DEPRECATED` macro allows us to remove (and usually replace)
features from VTK-m in minor releases while still following the conventions
of semantic versioning. The idea is that when we want to remove or replace
a feature, we first mark the old feature as deprecated. The old feature
will continue to work, but compilers that support it will start to issue a
warning that the use is deprecated and should stop being used. The
deprecated features should remain viable until at least the next major
version. At the next major version, deprecated features from the previous
version may be removed.
## Declaring things deprecated
Classes and methods are marked deprecated using the `VTKM_DEPRECATED`
macro. The first argument of `VTKM_DEPRECATED` should be set to the first
version in which the feature is deprecated. For example, if the last
released version of VTK-m was 1.5, and on the master branch a developer
wants to deprecate a class foo, then the `VTKM_DEPRECATED` release version
should be given as 1.6, which will be the next minor release of VTK-m. The
second argument of `VTKM_DEPRECATED`, which is optional but highly
encouraged, is a short message that should clue developers on how to update
their code to the new changes. For example, it could point to the
replacement class or method for the changed feature.
`VTKM_DEPRECATED` can be used to deprecate a class by adding it between the
`struct` or `class` keyword and the class name.
``` cpp
struct VTKM_DEPRECATED(1.6, "OldClass replaced with NewClass.") OldClass
{
};
```
Aliases can similarly be depreciated, except the `VTKM_DEPRECATED` macro
goes after the name in this case.
``` cpp
using OldAlias VTKM_DEPRECATED(1.6, "Use NewClass instead.") = NewClass;
```
Functions and methods are marked as deprecated by adding `VTKM_DEPRECATED`
as a modifier before the return value.
``` cpp
VTKM_EXEC_CONT
VTKM_DEPRECATED(1.6, "You must now specify a tolerance.") void ImportantMethod(double x)
{
this->ImportantMethod(x, 1e-6);
}
```
`enum`s can be deprecated like classes using similar syntax.
``` cpp
enum struct VTKM_DEPRECATED(1.7, "Use NewEnum instead.") OldEnum
{
OLD_VALUE
};
```
Individual items in an `enum` can also be marked as deprecated and
intermixed with regular items.
``` cpp
enum struct NewEnum
{
OLD_VALUE1 VTKM_DEPRECATED(1.7, "Use NEW_VALUE instead."),
NEW_VALUE,
OLD_VALUE2 VTKM_DEPRECATED(1.7) = 42
};
```
## Using deprecated items
Using deprecated items should work, but the compiler will give a warning.
That is the point. However, sometimes you need to legitimately use a
deprecated item without a warning. This is usually because you are
implementing another deprecated item or because you have a test for a
deprecated item (that can be easily removed with the deprecated bit). To
support this a pair of macros, `VTKM_DEPRECATED_SUPPRESS_BEGIN` and
`VTKM_DEPRECATED_SUPPRESS_END` are provided. Code that legitimately uses
deprecated items should be wrapped in these macros.
``` cpp
VTKM_EXEC_CONT
VTKM_DEPRECATED(1.6, "You must now specify both a value and tolerance.")
void ImportantMethod()
{
// It can be the case that to implement a deprecated method you need to
// use other deprecated features. To do that, just temporarily suppress
// those warnings.
VTKM_DEPRECATED_SUPPRESS_BEGIN
this->ImportantMethod(0.0);
VTKM_DEPRECATED_SUPPRESS_END
}
```

@ -0,0 +1,133 @@
# Updated Benchmark Framework
The benchmarking framework has been updated to use Google Benchmark.
A benchmark is now a single function, which is passed to a macro:
```
void MyBenchmark(::benchmark::State& state)
{
MyClass someClass;
// Optional: Add a descriptive label with additional benchmark details:
state.SetLabel("Blah blah blah.");
// Must use a vtkm timer to properly capture eg. CUDA execution times.
vtkm::cont::Timer timer;
for (auto _ : state)
{
someClass.Reset();
timer.Start();
someClass.DoWork();
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
// Optional: Report items and/or bytes processed per iteration in output:
state.SetItemsProcessed(state.iterations() * someClass.GetNumberOfItems());
state.SetBytesProcessed(state.iterations() * someClass.GetNumberOfBytes());
}
}
VTKM_BENCHMARK(MyBenchmark);
```
Google benchmark also makes it easy to implement parameter sweep benchmarks:
```
void MyParameterSweep(::benchmark::State& state)
{
// The current value in the sweep:
const vtkm::Id currentValue = state.range(0);
MyClass someClass;
someClass.SetSomeParameter(currentValue);
vtkm::cont::Timer timer;
for (auto _ : state)
{
someClass.Reset();
timer.Start();
someClass.DoWork();
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
VTKM_BENCHMARK_OPTS(MyBenchmark, ->ArgName("Param")->Range(32, 1024 * 1024));
```
will generate and launch several benchmarks, exploring the parameter space of
`SetSomeParameter` between the values of 32 and (1024*1024). The chain of
functions calls in the second argument is applied to an instance of
::benchmark::internal::Benchmark. See Google Benchmark's documentation for
more details.
For more complex benchmark configurations, the VTKM_BENCHMARK_APPLY macro
accepts a function with the signature
`void Func(::benchmark::internal::Benchmark*)` that may be used to generate
more complex configurations.
To instantiate a templated benchmark across a list of types, the
VTKM_BENCHMARK_TEMPLATE* macros take a vtkm::List of types as an additional
parameter. The templated benchmark function will be instantiated and called
for each type in the list:
```
template <typename T>
void MyBenchmark(::benchmark::State& state)
{
MyClass<T> someClass;
// Must use a vtkm timer to properly capture eg. CUDA execution times.
vtkm::cont::Timer timer;
for (auto _ : state)
{
someClass.Reset();
timer.Start();
someClass.DoWork();
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
}
VTKM_BENCHMARK_TEMPLATE(MyBenchmark, vtkm::List<vtkm::Float32, vtkm::Vec3f_32>);
```
The benchmarks are executed by calling the `VTKM_EXECUTE_BENCHMARKS(argc, argv)`
macro from `main`. There is also a `VTKM_EXECUTE_BENCHMARKS_PREAMBLE(argc, argv, some_string)`
macro that appends the contents of `some_string` to the Google Benchmark preamble.
If a benchmark is not compatible with some configuration, it may call
`state.SkipWithError("Error message");` on the `::benchmark::State` object and return. This is
useful, for instance in the filter tests when the input is not compatible with the filter.
When launching a benchmark executable, the following options are supported by Google Benchmark:
- `--benchmark_list_tests`: List all available tests.
- `--benchmark_filter="[regex]"`: Only run benchmark with names that match `[regex]`.
- `--benchmark_filter="-[regex]"`: Only run benchmark with names that DON'T match `[regex]`.
- `--benchmark_min_time=[float]`: Make sure each benchmark repetition gathers `[float]` seconds
of data.
- `--benchmark_repetitions=[int]`: Run each benchmark `[int]` times and report aggregate statistics
(mean, stdev, etc). A "repetition" refers to a single execution of the benchmark function, not
an "iteration", which is a loop of the `for(auto _:state){...}` section.
- `--benchmark_report_aggregates_only="true|false"`: If true, only the aggregate statistics are
reported (affects both console and file output). Requires `--benchmark_repetitions` to be useful.
- `--benchmark_display_aggregates_only="true|false"`: If true, only the aggregate statistics are
printed to the terminal. Any file output will still contain all repetition info.
- `--benchmark_format="console|json|csv"`: Specify terminal output format: human readable
(`console`) or `csv`/`json` formats.
- `--benchmark_out_format="console|json|csv"`: Specify file output format: human readable
(`console`) or `csv`/`json` formats.
- `--benchmark_out=[filename]`: Specify output file.
- `--benchmark_color="true|false"`: Toggle color output in terminal when using `console` output.
- `--benchmark_counters_tabular="true|false"`: Print counter information (e.g. bytes/sec, items/sec)
in the table, rather than appending them as a label.
For more information and examples of practical usage, take a look at the existing benchmarks in
vtk-m/benchmarking/.

@ -0,0 +1,29 @@
# Add `ListTagRemoveIf`
It is sometimes useful to remove types from `ListTag`s. This is especially
the case when combining lists of types together where some of the type
combinations may be invalid and should be removed. To handle this
situation, a new `ListTag` type is added: `ListTagRemoveIf`.
`ListTagRemoveIf` is a template structure that takes two arguments. The
first argument is another `ListTag` type to operate on. The second argument
is a template that acts as a predicate. The predicate takes a type and
declares a Boolean `value` that should be `true` if the type should be
removed and `false` if the type should remain.
Here is an example of using `ListTagRemoveIf` to get basic types that hold
only integral values.
``` cpp
template <typename T>
using IsRealValue =
std::is_same<
typename vtkm::TypeTraits<typename vtkm::VecTraits<T>::BaseComponentType>::NumericTag,
vtkm::TypeTraitsRealTag>;
using MixedTypes =
vtkm::ListTagBase<vtkm::Id, vtkm::FloatDefault, vtkm::Id3, vtkm::Vec3f>;
using IntegralTypes = vtkm::ListTagRemoveIf<MixedTypes, IsRealValue>;
// IntegralTypes now equivalent to vtkm::ListTagBase<vtkm::Id, vtkm::Id3>
```

55
docs/changelog/list.md Normal file

@ -0,0 +1,55 @@
# Replaced `vtkm::ListTag` with `vtkm::List`
The original `vtkm::ListTag` was designed when we had to support compilers
that did not provide C++11's variadic templates. Thus, the design hides
type lists, which were complicated to support.
Now that we support C++11, variadic templates are trivial and we can easily
create templated type aliases with `using`. Thus, it is now simpler to deal
with a template that lists types directly.
Hence, `vtkm::ListTag` is deprecated and `vtkm::List` is now supported. The
main difference between the two is that whereas `vtkm::ListTag` allowed you
to create a list by subclassing another list, `vtkm::List` cannot be
subclassed. (Well, it can be subclassed, but the subclass ceases to be
considered a list.) Thus, where before you would declare a list like
``` cpp
struct MyList : vtkm::ListTagBase<Type1, Type2, Type3>
{
};
```
you now make an alias
``` cpp
using MyList = vtkm::List<Type1, Type2, Type3>;
```
If the compiler reports the `MyList` type in an error or warning, it
actually uses the fully qualified `vtkm::List<Type1, Type2, Type3>`.
Although this makes errors more verbose, it makes it easier to diagnose
problems because the types are explicitly listed.
The new `vtkm::List` comes with a list of utility templates to manipulate
lists that mostly mirrors those in `vtkm::ListTag`: `VTKM_IS_LIST`,
`ListApply`, `ListSize`, `ListAt`, `ListIndexOf`, `ListHas`, `ListAppend`,
`ListIntersect`, `ListTransform`, `ListRemoveIf`, and `ListCross`. All of
these utilities become `vtkm::List<>` types (where applicable), which makes
them more consistent than the old `vtkm::ListTag` versions.
Thus, if you have a declaration like
``` cpp
vtkm::ListAppend(vtkm::List<Type1a, Type2a>, vtkm::List<Type1b, Type2b>>
```
this gets changed automatically to
``` cpp
vtkm::List<Type1a, Type2a, Type1b, Type2b>
```
This is in contrast to the equivalent old version, which would create a new
type for `vtkm::ListTagAppend` in addition to the ultimate actual list it
constructs.

@ -0,0 +1,11 @@
# Masks and Scatters Supported for 3D Scheduling
Previous to this change worklets that wanted to use non-default
`vtkm::worklet::Mask` or `vtkm::worklet::Scatter` wouldn't work when scheduled
to run across `vtkm::cont::CellSetStructured` or other `InputDomains` that
supported 3D scheduling.
This restriction was an inadvertent limitation of the VTK-m worklet scheduling
algorithm. Lifting the restriction and providing sufficient information has
been achieved in a manner that shouldn't degrade performance of any existing
worklets.

@ -0,0 +1,220 @@
# Scope ExecObjects with Tokens
When VTK-m's `ArrayHandle` was originally designed, it was assumed that the
control environment would run on a single thread. However, multiple users
have expressed realistic use cases in which they would like to control
VTK-m from multiple threads (for example, to control multiple devices).
Consequently, it is important that VTK-m's control classes work correctly
when used simultaneously from multiple threads.
The original `PrepareFor*` methods of `ArrayHandle` returned an object to
be used in the execution environment on a particular device that pointed to
data in the array. The pointer to the data was contingent on the state of
the `ArrayHandle` not changing. The assumption was that the calling code
would immediately use the returned execution environment object and would
not further change the `ArrayHandle` until done with the execution
environment object.
This assumption is broken if multiple threads are running in the control
environment. For example, if one thread has called `PrepareForInput` to get
an execution array portal, the portal or its data could become invalid if
another thread calls `PrepareForOutput` on the same array. Initially one
would think that a well designed program should not share `ArrayHandle`s in
this way, but there are good reasons to need to do so. For example, when
using `vtkm::cont::PartitionedDataSet` where multiple partitions share a
coordinate system (very common), it becomes unsafe to work on multiple
blocks in parallel on different devices.
What we really want is the code to be able to specify more explicitly when
the execution object is in use. Ideally, the execution object itself would
maintain the resources it is using. However, that will not work in this
case since the object has to pass from control to execution environment and
back. The resource allocation will break when the object is passed to an
offloaded device and back.
Because we cannot use the object itself to manage its own resources, we use
a proxy object we are calling a `Token`. The `Token` object manages the
scope of the return execution object. As long as the `Token` is still in
scope, the execution object will remain valid. When the `Token` is
destroyed (or `DetachFromAll` is called on it), then the execution object
is no longer protected.
When a `Token` is attached to an `ArrayHandle` to protect an execution
object, it's read or write mode is recorded. Multiple `Token`s can be
attached to read the `ArrayHandle` at the same time. However, only one
`Token` can be used to write to the `ArrayHandle`.
## Basic `ArrayHandle` use
The basic use of the `PrepareFor*` methods of `ArrayHandle` remain the
same. The only difference is the addition of a `Token` parameter.
``` cpp
template <typename Device>
void LowLevelArray(vtkm::cont::ArrayHandle<vtkm::Float32> array, Device)
{
vtkm::cont::Token token;
auto portal = array.PrepareForOutput(ARRAY_SIZE, Device{}, token);
// At this point, array is locked from anyone else from reading or modifying
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(MyKernel(portal), ARRAY_SIZE);
// When the function finishes, token goes out of scope and array opens up
// for other uses.
}
```
## Execution objects
To make sure that execution objects are scoped correctly, many changes
needed to be made to propagate a `Token` reference from the top of the
scope to where the execution object is actually made. The most noticeable
place for this was for implementations of
`vtkm::cont::ExecutionObjectBase`. Most implementations of
`ExecutionObjectBase` create an object that requires data from an
`ArrayHandle`.
Previously, a subclass of `ExecutionObjectBase` was expected to have a
method named `PrepareForExecution` that had a single argument: the device
tag (or id) to make an object for. Now, subclasses of `ExecutionObjectBase`
should have a `PrepareForExecution` that takes two arguments: the device
and a `Token` to use for scoping the execution object.
``` cpp
struct MyExecObject : vtkm::cont::ExecutionObjectBase
{
vtkm::cont::ArrayHandle<vtkm::Float32> Array;
template <typename Device>
VTKM_CONT
MyExec<Device> PrepareForExecution(Device device, vtkm::cont::Token& token)
{
MyExec<Device> object;
object.Portal = this->Array.PrepareForInput(device, token);
return object;
}
};
```
It actually still works to use the old style of `PrepareForExecution`.
However, you will get a deprecation warning (on supported compilers) when
you try to use it.
## Invoke and Dispatcher
The `Dispatcher` classes now internally define a `Token` object during the
call to `Invoke`. (Likewise, `Invoker` will have a `Token` defined during
its invoke.) This internal `Token` is used when preparing `ArrayHandle`s
and `ExecutionObject`s for the execution environment. (Details in the next
section on how that works.)
Because the invoke uses a `Token` to protect its arguments, it will block
the execution of other worklets attempting to access arrays in a way that
could cause read-write hazards. In the following example, the second
worklet will not be able to execute until the first worklet finishes.
``` cpp
vtkm::cont::Invoker invoke;
invoke(Worklet1{}, input, intermediate);
invoke(Worklet2{}, intermediate, output); // Will not execute until Worklet1 finishes.
```
That said, invocations _can_ share arrays if their use will not cause
read-write hazards. In particular, two invocations can both use the same
array if they are both strictly reading from it. In the following example,
both worklets can potentially execute at the same time.
``` cpp
vtkm::cont::Invoker invoke;
invoke(Worklet1{}, input, output1);
invoke(Worklet2{}, input, output2); // Will not block
```
The same `Token` is used for all arguments to the `Worklet`. This deatil is
important to prevent deadlocks if the same object is used in more than one
`Worklet` parameter. As a simple example, if a `Worklet` has a control
signature like
``` cpp
using ControlSignature = void(FieldIn, FieldOut);
```
it should continue to work to use the same array as both fields.
``` cpp
vtkm::cont::Invoker invoke;
invoke(Worklet1{}, array, array);
```
## Transport
The dispatch mechanism of worklets internally uses
`vtkm::cont::arg::Transport` objects to automatically move data from the
control environment to the execution environment. These `Transport` object
now take a `Token` when doing the transportation. This all happens under
the covers for most users.
## Control Portals
The `GetPortalConstControl` and `GetPortalControl` methods have been
deprecated. Instead, the methods `ReadPortal` and `WritePortal` should be
used. The calling signature is the same as their predecessors, but the
returned portal contains a `Token` as part of its state and prevents and
changes to the `ArrayHandle` it comes from. The `WritePortal` also prevents
other reads from the array.
The advantage is that the returned portal will always be valid. However, it
is now the case that a control portal can prevent something else from
running. This means that control portals should drop scope as soon as
possible. It is because of this behavior change that new methods were
created instead of altering the old ones.
## Deadlocks
Now that portal objects from `ArrayHandle`s have finite scope (as opposed
to able to be immediately invalidated), the scopes have the ability to
cause operations to block. This can cause issues if the `ArrayHandle` is
attempted to be used by multiple `Token`s at once.
Care should be taken to ensure that a single thread does not attempt to use
an `ArrayHandle` two ways at the same time.
``` cpp
auto portal = array.WritePortal();
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
portal.Set(index, /* An interesting value */);
}
vtkm::cont::Invoker invoke;
invoke(MyWorklet, array); // Oops. Deadlock here.
```
In this example, the last line deadlocks because `portal` is still holding
onto `array` for writing. When the worklet is invoked, it waits for
everything to stop writing to `array` so that it can be safely be read.
Instead, `portal` should be properly scoped.
``` cpp
{
auto portal = array.GetPortalControl();
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
portal.Set(index, /* An interesting value */);
}
}
vtkm::cont::Invoker invoke;
invoke(MyWorklet, array); // Runs fine because portal left scope
```
Alternately, you can call `Detach` on the portal, which will invalidate the
portal and unlock the `ArrayHandle`.
``` cpp
auto portal = array.WritePortal();
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
portal.Set(index, /* An interesting value */);
}
portal.Detach();
vtkm::cont::Invoker invoke;
invoke(MyWorklet, array); // Runs fine because portal detached
```

@ -0,0 +1,234 @@
# Shorter fancy array handle classnames
Many of the fancy `ArrayHandle`s use the generic builders like
`ArrayHandleTransform` and `ArrayHandleImplicit` for their implementation.
Such is fine, but because they use functors and other such generic items to
template their `Storage`, you can end up with very verbose classnames. This
is an issue for humans trying to discern classnames. It can also be an
issue for compilers that end up with very long resolved classnames that
might get truncated if they extend past what was expected.
The fix was for these classes to declare their own `Storage` tag and then
implement their `Storage` and `ArrayTransport` classes as trivial
subclasses of the generic `ArrayHandleImplicit` or `ArrayHandleTransport`.
As an added bonus, a lot of this shortening also means that storage that
relies on other array handles now are just typed by the storage of the
decorated type, not the array itself. This should make the types a little
more robust.
Here is a list of classes that were updated.
#### `ArrayHandleCast<TargetT, vtkm::cont::ArrayHandle<SourceT, SourceStorage>>`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagTransform<
vtkm::cont::ArrayHandle<SourceT, SourceStorage>,
vtkm::cont::internal::Cast<TargetT, SourceT>,
vtkm::cont::internal::Cast<SourceT, TargetT>>
```
New Storage:
``` cpp
vtkm::cont::StorageTagCast<SourceT, SourceStorage>
```
(Developer's note: Implementing this change to `ArrayHandleCast` was a much bigger PITA than expected.)
#### `ArrayHandleCartesianProduct<AH1, AH2, AH3>`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagCartesianProduct<
vtkm::cont::ArrayHandle<ValueType, StorageTag1,
vtkm::cont::ArrayHandle<ValueType, StorageTag2,
vtkm::cont::ArrayHandle<ValueType, StorageTag3>>
```
New storage:
``` cpp
vtkm::cont::StorageTagCartesianProduct<StorageTag1, StorageTag2, StorageTag3>
```
#### `ArrayHandleCompositeVector<AH1, AH2, ...>`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagCompositeVector<
tao::tuple<
vtkm::cont::ArrayHandle<ValueType, StorageType1>,
vtkm::cont::ArrayHandle<ValueType, StorageType2>,
...
>
>
```
New storage:
``` cpp
vtkm::cont::StorageTagCompositeVec<StorageType1, StorageType2>
```
#### `ArrayHandleConcatinate`
First an example with two simple types.
Old storage:
``` cpp
vtkm::cont::StorageTagConcatenate<
vtkm::cont::ArrayHandle<ValueType, StorageTag1>,
vtkm::cont::ArrayHandle<ValueType, StorageTag2>>
```
New storage:
``` cpp
vtkm::cont::StorageTagConcatenate<StorageTag1, StorageTag2>
```
Now a more specific example taken from the unit test of a concatination of a concatination.
Old storage:
``` cpp
vtkm::cont::StorageTagConcatenate<
vtkm::cont::ArrayHandleConcatenate<
vtkm::cont::ArrayHandle<ValueType, StorageTag1>,
vtkm::cont::ArrayHandle<ValueType, StorageTag2>>,
vtkm::cont::ArrayHandle<ValueType, StorageTag3>>
```
New storage:
``` cpp
vtkm::cont::StorageTagConcatenate<
vtkm::cont::StorageTagConcatenate<StorageTag1, StorageTag2>, StorageTag3>
```
#### `ArrayHandleConstant`
Old storage:
``` cpp
vtkm::cont::StorageTagImplicit<
vtkm::cont::detail::ArrayPortalImplicit<
vtkm::cont::detail::ConstantFunctor<ValueType>>>
```
New storage:
``` cpp
vtkm::cont::StorageTagConstant
```
#### `ArrayHandleCounting`
Old storage:
``` cpp
vtkm::cont::StorageTagImplicit<vtkm::cont::internal::ArrayPortalCounting<ValueType>>
```
New storage:
``` cpp
vtkm::cont::StorageTagCounting
```
#### `ArrayHandleGroupVec`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagGroupVec<
vtkm::cont::ArrayHandle<ValueType, StorageTag>, N>
```
New storage:
``` cpp
vtkm::cont::StorageTagGroupVec<StorageTag, N>
```
#### `ArrayHandleGroupVecVariable`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagGroupVecVariable<
vtkm::cont::ArrayHandle<ValueType, StorageTag1>,
vtkm::cont::ArrayHandle<vtkm::Id, StorageTag2>>
```
New storage:
``` cpp
vtkm::cont::StorageTagGroupVecVariable<StorageTag1, StorageTag2>
```
#### `ArrayHandleIndex`
Old storage:
``` cpp
vtkm::cont::StorageTagImplicit<
vtkm::cont::detail::ArrayPortalImplicit<vtkm::cont::detail::IndexFunctor>>
```
New storage:
``` cpp
vtkm::cont::StorageTagIndex
```
#### `ArrayHandlePermutation`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagPermutation<
vtkm::cont::ArrayHandle<vtkm::Id, StorageTag1>,
vtkm::cont::ArrayHandle<ValueType, StorageTag2>>
```
New storage:
``` cpp
vtkm::cont::StorageTagPermutation<StorageTag1, StorageTag2>
```
#### `ArrayHandleReverse`
Old storage:
``` cpp
vtkm::cont::StorageTagReverse<vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTag>>
```
New storage:
``` cpp
vtkm::cont::StorageTagReverse<StorageTag>
```
#### `ArrayHandleUniformPointCoordinates`
Old storage:
``` cpp
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>
```
New Storage:
``` cpp
vtkm::cont::StorageTagUniformPoints
```
#### `ArrayHandleView`
Old storage:
``` cpp
vtkm::cont::StorageTagView<vtkm::cont::ArrayHandle<ValueType, StorageTag>>
```
New storage:
``` cpp
'vtkm::cont::StorageTagView<StorageTag>
```
#### `ArrayPortalZip`
Old storage:
``` cpp
vtkm::cont::internal::StorageTagZip<
vtkm::cont::ArrayHandle<ValueType1, StorageTag1>,
vtkm::cont::ArrayHandle<ValueType2, StorageTag2>>
```
New storage:
``` cpp
vtkm::cont::StorageTagZip<StorageTag1, StorageTag2>
```

@ -89,11 +89,11 @@ int main(int argc, char* argv[])
vtkm::Id2 vdims;
inFile >> vdims[0];
inFile >> vdims[1];
std::size_t nVertices = static_cast<std::size_t>(vdims[0] * vdims[1]);
std::size_t numVertices = static_cast<std::size_t>(vdims[0] * vdims[1]);
// read data
std::vector<vtkm::Float32> values(nVertices);
for (std::size_t vertex = 0; vertex < nVertices; vertex++)
std::vector<vtkm::Float32> values(numVertices);
for (std::size_t vertex = 0; vertex < numVertices; vertex++)
{
inFile >> values[vertex];
}

@ -90,11 +90,11 @@ int main(int argc, char* argv[])
inFile >> vdims[0];
inFile >> vdims[1];
inFile >> vdims[2];
std::size_t nVertices = static_cast<std::size_t>(vdims[0] * vdims[1] * vdims[2]);
std::size_t numVertices = static_cast<std::size_t>(vdims[0] * vdims[1] * vdims[2]);
// read data
std::vector<vtkm::Float32> values(nVertices);
for (std::size_t vertex = 0; vertex < nVertices; vertex++)
std::vector<vtkm::Float32> values(numVertices);
for (std::size_t vertex = 0; vertex < numVertices; vertex++)
{
inFile >> values[vertex];
}

@ -65,6 +65,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/filter/ContourTreeUniformAugmented.h>
@ -91,17 +92,16 @@ VTKM_THIRDPARTY_POST_INCLUDE
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>
#include <utility>
#include <vector>
#define DEBUG_TIMING
using ValueType = vtkm::Float32;
using BranchType = vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch<ValueType>;
namespace cppp2_ns = vtkm::worklet::contourtree_augmented;
namespace ctaug_ns = vtkm::worklet::contourtree_augmented;
// Simple helper class for parsing the command line options
class ParseCL
@ -173,24 +173,28 @@ int main(int argc, char* argv[])
MPI_Comm_size(comm, &size);
int numBlocks = size;
int blocksPerRank = 1;
if (rank == 0)
{
std::cout << "Running with MPI. #ranks=" << size << std::endl;
}
#endif
// initialize vtkm-m (e.g., logging via -v and device via the -d option)
vtkm::cont::InitializeOptions vtkm_initialize_options =
vtkm::cont::InitializeOptions::RequireDevice;
vtkm::cont::InitializeResult vtkm_config =
vtkm::cont::Initialize(argc, argv, vtkm_initialize_options);
auto device = vtkm_config.Device;
#ifdef WITH_MPI
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Info, rank == 0, "Running with MPI. #ranks=" << size);
#else
std::cout << "Single node run" << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Single node run");
int rank = 0;
#endif
// Setup timing
vtkm::Float64 prevTime = 0;
vtkm::Float64 currTime = 0;
vtkm::cont::Timer totalTime;
totalTime.Start();
if (rank == 0)
{
std::cout << "ContourTreePPP2Mesh <options> <fileName>" << std::endl;
}
////////////////////////////////////////////
// Parse the command line options
@ -214,59 +218,30 @@ int main(int argc, char* argv[])
// We need the fully augmented tree to compute the branch decomposition
if (computeBranchDecomposition && (computeRegularStructure != 1))
{
std::cout << "Regular structure is required for branch decomposition."
" Disabling branch decomposition"
<< std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Regular structure is required for branch decomposition."
" Disabling branch decomposition");
computeBranchDecomposition = false;
}
std::string device("default");
if (parser.hasOption("--device"))
{
device = parser.getOption("--device");
auto& rtTracker = vtkm::cont::GetRuntimeDeviceTracker();
if (device == "serial" && rtTracker.CanRunOn(vtkm::cont::DeviceAdapterTagSerial()))
{
rtTracker.ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
}
else if (device == "openmp" && rtTracker.CanRunOn(vtkm::cont::DeviceAdapterTagOpenMP()))
{
rtTracker.ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP());
}
else if (device == "tbb" && rtTracker.CanRunOn(vtkm::cont::DeviceAdapterTagTBB()))
{
rtTracker.ForceDevice(vtkm::cont::DeviceAdapterTagTBB());
}
else if (device == "cuda" && rtTracker.CanRunOn(vtkm::cont::DeviceAdapterTagCuda()))
{
rtTracker.ForceDevice(vtkm::cont::DeviceAdapterTagCuda());
}
else
{
std::cout << "Invalid or unavialable device adapter: " << device << std::endl;
return EXIT_FAILURE;
}
}
#ifdef ENABLE_SET_NUM_THREADS
int numThreads = tbb::task_scheduler_init::default_num_threads();
if (parser.hasOption("--numThreads"))
{
if (device == "default" &&
vtkm::cont::GetRuntimeDeviceTracker().CanRunOn(vtkm::cont::DeviceAdapterTagTBB()))
// Print warning about mismatch between the --numThreads and -d/--device opton
VTKM_LOG_S_IF(vtkm::cont::LogLevel::Warn,
device != vtkm::cont::DeviceAdapterTagTBB,
"WARNING: Mismatch between --numThreads and -d/--device option."
"numThreads option requires the use of TBB as device. "
"Ignoring the numThread option.");
// Set the number of threads to be used for TBB
if (device == vtkm::cont::DeviceAdapterTagTBB)
{
std::cout << "--numThreads specified without device. Forcing device as tbb.";
device = "tbb";
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagTBB());
}
numThreads = std::stoi(parser.getOption("--numThreads"));
if (device != "tbb")
{
std::cout << "numThreads will be ignored for devices other than tbb";
numThreads = std::stoi(parser.getOption("--numThreads"));
tbb::task_scheduler_init schedulerInit(numThreads);
}
}
tbb::task_scheduler_init schedulerInit(numThreads);
#endif
// Iso value selection parameters
@ -297,21 +272,28 @@ int main(int argc, char* argv[])
usePersistenceSorter = false;
if ((numLevels > 0) && (!computeBranchDecomposition))
{
std::cout << "Iso level selection only available when branch decomposition is enabled."
" Disabling iso value selection"
<< std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Iso level selection only available when branch decomposition is enabled. "
"Disabling iso value selection");
numLevels = 0;
}
if (rank == 0 && (argc < 2 || parser.hasOption("--help") || parser.hasOption("-h")))
{
std::cout << "Parameter is <fileName>" << std::endl;
std::cout << "File is expected to be ASCII with either: " << std::endl;
std::cout << "ContourTreeAugmented <options> <fileName>" << std::endl;
std::cout << std::endl;
std::cout << "<fileName> Name of the input data file." << std::endl;
std::cout << "The file is expected to be ASCII with either: " << std::endl;
std::cout << " - xdim ydim integers for 2D or" << std::endl;
std::cout << " - xdim ydim zdim integers for 3D" << std::endl;
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
std::cout << std::endl;
std::cout << "----------------------------- VTKM Options -----------------------------"
<< std::endl;
std::cout << vtkm_config.Usage << std::endl;
std::cout << std::endl;
std::cout << "------------------------- Contour Tree Options -------------------------"
<< std::endl;
std::cout << "Options: (Bool options are give via int, i.e. =0 for False and =1 for True)"
<< std::endl;
std::cout << "--mc Use marching cubes interpolation for contour tree calculation. "
@ -328,14 +310,13 @@ int main(int argc, char* argv[])
"Requires --augmentTree (Default=True)"
<< std::endl;
std::cout << "--printCT Print the contour tree. (Default=False)" << std::endl;
std::cout << "--device Set the device to use (serial, openmp, tbb, cuda). "
"Use the default device if unspecified"
<< std::endl;
#ifdef ENABLE_SET_NUM_THREADS
std::cout << "--numThreads Specifiy the number of threads to use. Available only with TBB."
<< std::endl;
#endif
std::cout << std::endl;
std::cout << "---------------------- Isovalue Selection Options ----------------------"
<< std::endl;
std::cout << "Isovalue selection options: (require --branchDecomp=1 and augmentTree=1)"
<< std::endl;
std::cout << "--levels=<int> Number of iso-contour levels to be used (default=0, i.e., "
@ -352,6 +333,8 @@ int main(int argc, char* argv[])
<< std::endl;
std::cout << "--method=<int> Method used for selecting relevant iso-values. (default=0)"
<< std::endl;
std::cout << std::endl;
#ifdef WITH_MPI
MPI_Finalize();
#endif
@ -360,31 +343,60 @@ int main(int argc, char* argv[])
if (rank == 0)
{
std::cout << "Settings:" << std::endl;
std::cout << " filename=" << filename << std::endl;
std::cout << " device=" << device << std::endl;
std::cout << " mc=" << useMarchingCubes << std::endl;
std::cout << " augmentTree=" << computeRegularStructure << std::endl;
std::cout << " branchDecomp=" << computeBranchDecomposition << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " ------------ Settings -----------"
<< std::endl
<< " filename="
<< filename
<< std::endl
<< " device="
<< device.GetName()
<< std::endl
<< " mc="
<< useMarchingCubes
<< std::endl
<< " augmentTree="
<< computeRegularStructure
<< std::endl
<< " branchDecomp="
<< computeBranchDecomposition
<< std::endl
<<
#ifdef WITH_MPI
std::cout << " nblocks=" << numBlocks << std::endl;
" nblocks=" << numBlocks << std::endl
<<
#endif
#ifdef ENABLE_SET_NUM_THREADS
std::cout << " numThreads=" << numThreads << std::endl;
" numThreads=" << numThreads << std::endl
<<
#endif
std::cout << " computeIsovalues=" << (numLevels > 0) << std::endl;
if (numLevels > 0)
{
std::cout << " levels=" << numLevels << std::endl;
std::cout << " eps=" << eps << std::endl;
std::cout << " comp" << numComp << std::endl;
std::cout << " type=" << contourType << std::endl;
std::cout << " method=" << contourSelectMethod << std::endl;
std::cout << " mc=" << useMarchingCubes << std::endl;
std::cout << " use" << (usePersistenceSorter ? "PersistenceSorter" : "VolumeSorter")
<< std::endl;
}
std::cout << std::endl;
" computeIsovalues=" << (numLevels > 0));
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Info,
numLevels > 0,
std::endl
<< " ------------ Settings Isolevel Selection -----------"
<< std::endl
<< " levels="
<< numLevels
<< std::endl
<< " eps="
<< eps
<< std::endl
<< " comp"
<< numComp
<< std::endl
<< " type="
<< contourType
<< std::endl
<< " method="
<< contourSelectMethod
<< std::endl
<< " mc="
<< useMarchingCubes
<< std::endl
<< " use"
<< (usePersistenceSorter ? "PersistenceSorter" : "VolumeSorter"));
}
currTime = totalTime.GetElapsedTime();
vtkm::Float64 startUpTime = currTime - prevTime;
@ -449,31 +461,40 @@ int main(int argc, char* argv[])
// Compute the number of vertices, i.e., xdim * ydim * zdim
unsigned short nDims = static_cast<unsigned short>(dims.size());
std::size_t nVertices = static_cast<std::size_t>(
std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<std::size_t>()));
std::size_t numVertices = static_cast<std::size_t>(
std::accumulate(dims.begin(), dims.end(), std::size_t(1), std::multiplies<std::size_t>()));
// Print the mesh metadata
if (rank == 0)
{
std::cout << "Number of dimensions: " << nDims << std::endl;
std::cout << "Number of mesh vertices: " << nVertices << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " ---------------- Input Mesh Properties --------------"
<< std::endl
<< " Number of dimensions: "
<< nDims
<< std::endl
<< " Number of mesh vertices: "
<< numVertices
<< std::endl);
}
// Check for fatal input errors
// Check the the number of dimensiosn is either 2D or 3D
bool invalidNumDimensions = (nDims < 2 || nDims > 3);
// Check if marching cubes is enabled for non 3D data
bool invalidMCOption = (useMarchingCubes && nDims != 3);
if (rank == 0)
{
if (invalidNumDimensions)
{
std::cout << "The input mesh is " << nDims << "D. Input data must be either 2D or 3D."
<< std::endl;
}
if (invalidMCOption)
{
std::cout << "The input mesh is " << nDims
<< "D. Contour tree using marching cubes only supported for 3D data." << std::endl;
}
}
// Log any errors if found on rank 0
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
invalidNumDimensions && (rank == 0),
"The input mesh is " << nDims << "D. "
"The input data must be either 2D or 3D.");
VTKM_LOG_IF_S(
vtkm::cont::LogLevel::Error,
invalidMCOption && (rank == 0),
"The input mesh is " << nDims << "D. "
<< "Contour tree using marching cubes is only supported for 3D data.");
// If we found any errors in the setttings than finalize MPI and exit the execution
if (invalidNumDimensions || invalidMCOption)
{
#ifdef WITH_MPI
@ -483,8 +504,8 @@ int main(int argc, char* argv[])
}
// Read data
std::vector<ValueType> values(nVertices);
for (std::size_t vertex = 0; vertex < nVertices; ++vertex)
std::vector<ValueType> values(numVertices);
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
{
inFile >> values[vertex];
}
@ -505,16 +526,16 @@ int main(int argc, char* argv[])
if (nDims == 2)
{
vtkm::Id2 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[0]);
vdims[1] = static_cast<vtkm::Id>(dims[1]);
vdims[0] = static_cast<vtkm::Id>(dims[1]);
vdims[1] = static_cast<vtkm::Id>(dims[0]);
inDataSet = dsb.Create(vdims);
}
// 3D data
else
{
vtkm::Id3 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[0]);
vdims[1] = static_cast<vtkm::Id>(dims[1]);
vdims[0] = static_cast<vtkm::Id>(dims[1]);
vdims[1] = static_cast<vtkm::Id>(dims[0]);
vdims[2] = static_cast<vtkm::Id>(dims[2]);
inDataSet = dsb.Create(vdims);
}
@ -537,20 +558,19 @@ int main(int argc, char* argv[])
localBlockIndices.Allocate(blocksPerRank);
localBlockOrigins.Allocate(blocksPerRank);
localBlockSizes.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.GetPortalControl();
auto localBlockOriginsPortal = localBlockOrigins.GetPortalControl();
auto localBlockSizesPortal = localBlockSizes.GetPortalControl();
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
{
vtkm::Id lastDimSize =
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
if (size > (lastDimSize / 2.))
{
if (rank == 0)
{
std::cout << "Number of ranks to large for data. Use " << lastDimSize / 2
<< "or fewer ranks" << std::endl;
}
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
rank == 0,
"Number of ranks to large for data. Use " << lastDimSize / 2
<< "or fewer ranks");
MPI_Finalize();
return EXIT_FAILURE;
}
@ -629,7 +649,7 @@ int main(int argc, char* argv[])
prevTime = currTime;
// Convert the mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreePPP2 filter(useMarchingCubes, computeRegularStructure);
vtkm::filter::ContourTreeAugmented filter(useMarchingCubes, computeRegularStructure);
#ifdef WITH_MPI
filter.SetSpatialDecomposition(
@ -645,66 +665,41 @@ int main(int argc, char* argv[])
vtkm::Float64 computeContourTreeTime = currTime - prevTime;
prevTime = currTime;
#ifdef WITH_MPI
#ifdef DEBUG_PRINT
if (rank == 0)
{
std::cout << "----- rank=" << rank << " ----Final Contour Tree Data----------------------------"
<< std::endl;
filter.GetContourTree().PrintContent();
vtkm::worklet::contourtree_augmented::printIndices("Mesh Sort Order", filter.GetSortOrder());
}
#endif
#endif
#ifdef DEBUG_TIMING
if (rank == 0)
{
std::cout << "----------------------- " << rank << " --------------------------------------"
<< std::endl;
std::cout << "-------------------Contour Tree Timings----------------------" << std::endl;
// Get the timings from the contour tree computation
const std::vector<std::pair<std::string, vtkm::Float64>>& contourTreeTimings =
filter.GetTimings();
for (std::size_t i = 0; i < contourTreeTimings.size(); ++i)
std::cout << std::setw(42) << std::left << contourTreeTimings[i].first << ": "
<< contourTreeTimings[i].second << " seconds" << std::endl;
}
#endif
////////////////////////////////////////////
// Compute the branch decomposition
////////////////////////////////////////////
if (rank == 0 && computeBranchDecomposition && computeRegularStructure)
{
// Time branch decompostion
vtkm::cont::Timer branchDecompTimer;
branchDecompTimer.Start();
// compute the volume for each hyperarc and superarc
cppp2_ns::IdArrayType superarcIntrinsicWeight;
cppp2_ns::IdArrayType superarcDependentWeight;
cppp2_ns::IdArrayType supernodeTransferWeight;
cppp2_ns::IdArrayType hyperarcDependentWeight;
cppp2_ns::ProcessContourTree::ComputeVolumeWeights(filter.GetContourTree(),
ctaug_ns::IdArrayType superarcIntrinsicWeight;
ctaug_ns::IdArrayType superarcDependentWeight;
ctaug_ns::IdArrayType supernodeTransferWeight;
ctaug_ns::IdArrayType hyperarcDependentWeight;
ctaug_ns::ProcessContourTree::ComputeVolumeWeights(filter.GetContourTree(),
filter.GetNumIterations(),
superarcIntrinsicWeight, // (output)
superarcDependentWeight, // (output)
supernodeTransferWeight, // (output)
hyperarcDependentWeight); // (output)
std::cout << std::setw(42) << std::left << "Compute Volume Weights"
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
// Record the timings for the branch decomposition
std::stringstream timingsStream; // Use a string stream to log in one message
timingsStream << std::endl;
timingsStream << " --------------- Branch Decomposition Timings " << rank
<< " --------------" << std::endl;
timingsStream << " " << std::setw(38) << std::left << "Compute Volume Weights"
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
branchDecompTimer.Start();
// compute the branch decomposition by volume
cppp2_ns::IdArrayType whichBranch;
cppp2_ns::IdArrayType branchMinimum;
cppp2_ns::IdArrayType branchMaximum;
cppp2_ns::IdArrayType branchSaddle;
cppp2_ns::IdArrayType branchParent;
cppp2_ns::ProcessContourTree::ComputeVolumeBranchDecomposition(filter.GetContourTree(),
ctaug_ns::IdArrayType whichBranch;
ctaug_ns::IdArrayType branchMinimum;
ctaug_ns::IdArrayType branchMaximum;
ctaug_ns::IdArrayType branchSaddle;
ctaug_ns::IdArrayType branchParent;
ctaug_ns::ProcessContourTree::ComputeVolumeBranchDecomposition(filter.GetContourTree(),
superarcDependentWeight,
superarcIntrinsicWeight,
whichBranch, // (output)
@ -712,8 +707,10 @@ int main(int argc, char* argv[])
branchMaximum, // (output)
branchSaddle, // (output)
branchParent); // (output)
std::cout << std::setw(42) << std::left << "Compute Volume Branch Decomposition"
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
// Record and log the branch decompostion timings
timingsStream << " " << std::setw(38) << std::left << "Compute Volume Branch Decomposition"
<< ": " << branchDecompTimer.GetElapsedTime() << " seconds" << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Info, timingsStream.str());
//----main branch decompostion end
//----Isovalue seleciton start
@ -733,9 +730,9 @@ int main(int argc, char* argv[])
// create explicit representation of the branch decompostion from the array representation
BranchType* branchDecompostionRoot =
cppp2_ns::ProcessContourTree::ComputeBranchDecomposition<ValueType>(
filter.GetContourTree().superparents,
filter.GetContourTree().supernodes,
ctaug_ns::ProcessContourTree::ComputeBranchDecomposition<ValueType>(
filter.GetContourTree().Superparents,
filter.GetContourTree().Supernodes,
whichBranch,
branchMinimum,
branchMaximum,
@ -746,11 +743,11 @@ int main(int argc, char* argv[])
dataFieldIsSorted);
#ifdef DEBUG_PRINT
branchDecompostionRoot->print(std::cout);
branchDecompostionRoot->PrintBranchDecomposition(std::cout);
#endif
// Simplify the contour tree of the branch decompostion
branchDecompostionRoot->simplifyToSize(numComp, usePersistenceSorter);
branchDecompostionRoot->SimplifyToSize(numComp, usePersistenceSorter);
// Compute the relevant iso-values
std::vector<ValueType> isoValues;
@ -759,7 +756,7 @@ int main(int argc, char* argv[])
default:
case 0:
{
branchDecompostionRoot->getRelevantValues(static_cast<int>(contourType), eps, isoValues);
branchDecompostionRoot->GetRelevantValues(static_cast<int>(contourType), eps, isoValues);
}
break;
case 1:
@ -767,30 +764,32 @@ int main(int argc, char* argv[])
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PiecewiseLinearFunction<
ValueType>
plf;
branchDecompostionRoot->accumulateIntervals(static_cast<int>(contourType), eps, plf);
branchDecompostionRoot->AccumulateIntervals(static_cast<int>(contourType), eps, plf);
isoValues = plf.nLargest(static_cast<unsigned int>(numLevels));
}
break;
}
// Print the compute iso values
std::cout << std::endl;
std::cout << "Isovalue Suggestions" << std::endl;
std::cout << "====================" << std::endl;
std::stringstream isoStream; // Use a string stream to log in one message
isoStream << std::endl;
isoStream << " ------------------- Isovalue Suggestions --------------------" << std::endl;
std::sort(isoValues.begin(), isoValues.end());
std::cout << "Isovalues: ";
isoStream << " Isovalues: ";
for (ValueType val : isoValues)
std::cout << val << " ";
std::cout << std::endl;
{
isoStream << val << " ";
}
isoStream << std::endl;
// Unique isovalues
std::vector<ValueType>::iterator it = std::unique(isoValues.begin(), isoValues.end());
isoValues.resize(static_cast<std::size_t>(std::distance(isoValues.begin(), it)));
std::cout << isoValues.size() << " Unique Isovalues: ";
isoStream << " Unique Isovalues (" << isoValues.size() << "):";
for (ValueType val : isoValues)
std::cout << val << " ";
std::cout << std::endl;
std::cout << std::endl;
{
isoStream << val << " ";
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info, isoStream.str());
} //end if compute isovalue
}
@ -807,13 +806,12 @@ int main(int argc, char* argv[])
{
std::cout << "Contour Tree" << std::endl;
std::cout << "============" << std::endl;
cppp2_ns::EdgePairArray saddlePeak;
cppp2_ns::ProcessContourTree::CollectSortedSuperarcs(
ctaug_ns::EdgePairArray saddlePeak;
ctaug_ns::ProcessContourTree::CollectSortedSuperarcs(
filter.GetContourTree(), filter.GetSortOrder(), saddlePeak);
cppp2_ns::printEdgePairArray(saddlePeak);
ctaug_ns::PrintEdgePairArray(saddlePeak);
}
#ifdef DEBUG_TIMING
#ifdef WITH_MPI
// Force a simple round-robin on the ranks for the summary prints. Its not perfect for MPI but
// it works well enough to sort the summaries from the ranks for small-scale debugging.
@ -824,52 +822,117 @@ int main(int argc, char* argv[])
MPI_Recv(&temp, 1, MPI_INT, (rank - 1), 0, comm, &status);
}
#endif
std::cout << "---------------------------" << rank << "----------------------------------"
<< std::endl;
std::cout << "--------------------------Totals-----------------------------" << std::endl;
std::cout << std::setw(42) << std::left << "Start-up"
<< ": " << startUpTime << " seconds" << std::endl;
std::cout << std::setw(42) << std::left << "Data Read"
<< ": " << dataReadTime << " seconds" << std::endl;
std::cout << std::setw(42) << std::left << "Build VTKM Dataset"
<< ": " << buildDatasetTime << " seconds" << std::endl;
std::cout << std::setw(42) << std::left << "Compute Contour Tree"
<< ": " << computeContourTreeTime << " seconds" << std::endl;
if (computeBranchDecomposition)
{
std::cout << std::setw(42) << std::left << "Compute Branch Decomposition"
<< ": " << computeBranchDecompTime << " seconds" << std::endl;
}
currTime = totalTime.GetElapsedTime();
//vtkm::Float64 miscTime = currTime - startUpTime - dataReadTime - buildDatasetTime - computeContourTreeTime;
//if(computeBranchDecomposition) miscTime -= computeBranchDecompTime;
//std::cout<<std::setw(42)<<std::left<<"Misc. Times"<<": "<<miscTime<<" seconds"<<std::endl;
std::cout << std::setw(42) << std::left << "Total Time"
<< ": " << currTime << " seconds" << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " -------------------------- Totals "
<< rank
<< " -----------------------------"
<< std::endl
<< std::setw(42)
<< std::left
<< " Start-up"
<< ": "
<< startUpTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Data Read"
<< ": "
<< dataReadTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Build VTKM Dataset"
<< ": "
<< buildDatasetTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Compute Contour Tree"
<< ": "
<< computeContourTreeTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Compute Branch Decomposition"
<< ": "
<< computeBranchDecompTime
<< " seconds"
<< std::endl
<< std::setw(42)
<< std::left
<< " Total Time"
<< ": "
<< currTime
<< " seconds");
std::cout << "-------------------------------------------------------------" << std::endl;
std::cout << "----------------Contour Tree Array Sizes---------------------" << std::endl;
const cppp2_ns::ContourTree& ct = filter.GetContourTree();
std::cout << std::setw(42) << std::left << "#Nodes"
<< ": " << ct.nodes.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Arcs"
<< ": " << ct.arcs.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Superparents"
<< ": " << ct.superparents.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Superarcs"
<< ": " << ct.superarcs.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Supernodes"
<< ": " << ct.supernodes.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Hyperparents"
<< ": " << ct.hyperparents.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#WhenTransferred"
<< ": " << ct.whenTransferred.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Hypernodes"
<< ": " << ct.hypernodes.GetNumberOfValues() << std::endl;
std::cout << std::setw(42) << std::left << "#Hyperarcs"
<< ": " << ct.hyperarcs.GetNumberOfValues() << std::endl;
const ctaug_ns::ContourTree& ct = filter.GetContourTree();
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
std::endl
<< " ---------------- Contour Tree Array Sizes ---------------------"
<< std::endl
<< std::setw(42)
<< std::left
<< " #Nodes"
<< ": "
<< ct.Nodes.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Arcs"
<< ": "
<< ct.Arcs.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Superparents"
<< ": "
<< ct.Superparents.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Superarcs"
<< ": "
<< ct.Superarcs.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Supernodes"
<< ": "
<< ct.Supernodes.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Hyperparents"
<< ": "
<< ct.Hyperparents.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #WhenTransferred"
<< ": "
<< ct.WhenTransferred.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Hypernodes"
<< ": "
<< ct.Hypernodes.GetNumberOfValues()
<< std::endl
<< std::setw(42)
<< std::left
<< " #Hyperarcs"
<< ": "
<< ct.Hyperarcs.GetNumberOfValues()
<< std::endl);
// Flush ouput streams just to make sure everything has been logged (in particular when using MPI)
std::cout << std::flush;
std::cerr << std::flush;
#ifdef WITH_MPI
// Let the next rank know that it is time to print their summary.
@ -879,7 +942,6 @@ int main(int argc, char* argv[])
MPI_Send(&message, 1, MPI_INT, (rank + 1), 0, comm);
}
#endif
#endif // DEBUG_TIMING
#ifdef WITH_MPI
MPI_Finalize();

@ -53,7 +53,7 @@
struct GameOfLifePolicy : public vtkm::filter::PolicyBase<GameOfLifePolicy>
{
using FieldTypeList = vtkm::ListTagBase<vtkm::UInt8, vtkm::Vec4ui_8>;
using FieldTypeList = vtkm::List<vtkm::UInt8, vtkm::Vec4ui_8>;
};
struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood

@ -47,7 +47,7 @@ class HelloField : public vtkm::filter::FilterField<HelloField>
{
public:
// Specify that this filter operates on 3-vectors
using SupportedTypes = vtkm::TypeListTagFieldVec3;
using SupportedTypes = vtkm::TypeListFieldVec3;
template <typename FieldType, typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet,

@ -43,8 +43,8 @@ VTKM_CONT vtkm::cont::ArrayHandle<T> CreateArray(T min, T max, vtkm::Id numVals)
vtkm::cont::ArrayHandle<T> handle;
handle.Allocate(numVals);
std::generate(vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalControl()),
vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalControl()),
std::generate(vtkm::cont::ArrayPortalToIteratorBegin(handle.WritePortal()),
vtkm::cont::ArrayPortalToIteratorEnd(handle.WritePortal()),
[&]() { return static_cast<T>(dis(gen)); });
return handle;
}
@ -92,7 +92,7 @@ int main(int argc, char* argv[])
vtkm::cont::ArrayHandle<vtkm::Id> bins;
result.GetPartition(0).GetField("histogram").GetData().CopyTo(bins);
auto binPortal = bins.GetPortalConstControl();
auto binPortal = bins.ReadPortal();
if (rank == 0)
{
// print histogram.

@ -25,7 +25,7 @@ public:
//currently the HistogramMPI filter only works on scalar data.
//this mainly has to do with getting the ranges for each bin
//would require returning a more complex value type
using SupportedTypes = vtkm::TypeListTagScalarAll;
using SupportedTypes = vtkm::TypeListScalarAll;
//Construct a HistogramMPI with a default of 10 bins
VTKM_CONT

@ -58,8 +58,8 @@ public:
// reduce local bins first.
vtkm::cont::ArrayHandle<vtkm::Id> local;
local.Allocate(numBins);
std::fill(vtkm::cont::ArrayPortalToIteratorBegin(local.GetPortalControl()),
vtkm::cont::ArrayPortalToIteratorEnd(local.GetPortalControl()),
std::fill(vtkm::cont::ArrayPortalToIteratorBegin(local.WritePortal()),
vtkm::cont::ArrayPortalToIteratorEnd(local.WritePortal()),
static_cast<vtkm::Id>(0));
for (const auto& lbins : this->LocalBlocks)
{
@ -70,8 +70,8 @@ public:
// converting to std::vector
std::vector<vtkm::Id> send_buf(static_cast<std::size_t>(numBins));
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(local.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(local.GetPortalConstControl()),
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(local.ReadPortal()),
vtkm::cont::ArrayPortalToIteratorEnd(local.ReadPortal()),
send_buf.begin());
std::vector<vtkm::Id> recv_buf(static_cast<std::size_t>(numBins));
@ -88,7 +88,7 @@ public:
local.Allocate(numBins);
std::copy(recv_buf.begin(),
recv_buf.end(),
vtkm::cont::ArrayPortalToIteratorBegin(local.GetPortalControl()));
vtkm::cont::ArrayPortalToIteratorBegin(local.WritePortal()));
return local;
}
return vtkm::cont::ArrayHandle<vtkm::Id>();
@ -158,7 +158,7 @@ inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::PartitionedData
{
throw vtkm::cont::ErrorFilterExecution("expecting scalar field.");
}
this->ComputedRange = handle.GetPortalConstControl().Get(0);
this->ComputedRange = handle.ReadPortal().Get(0);
}
}

@ -65,7 +65,7 @@ vtkm::cont::DataSet make3DRectilinearDataSet(double time)
double vec[3];
double loc[3] = { i * xdiff + xmin, j * ydiff + ymax, k * zdiff + zmin };
field.calculateVelocity(loc, time, vec);
velocityField.GetPortalControl().Set(count, vtkm::Vec3f_64(vec[0], vec[1], vec[2]));
velocityField.WritePortal().Set(count, vtkm::Vec3f_64(vec[0], vec[1], vec[2]));
count++;
}
}

@ -25,8 +25,7 @@ using RuntimeTaskQueue = TaskQueue<std::function<void()>>;
class MultiDeviceGradient : public vtkm::filter::FilterField<MultiDeviceGradient>
{
public:
using SupportedTypes =
vtkm::ListTagBase<vtkm::Float32, vtkm::Float64, vtkm::Vec3f_32, vtkm::Vec3f_64>;
using SupportedTypes = vtkm::List<vtkm::Float32, vtkm::Float64, vtkm::Vec3f_32, vtkm::Vec3f_64>;
//Construct a MultiDeviceGradient and worker pool
VTKM_CONT

@ -57,20 +57,21 @@ int main(int argc, char** argv)
//create seeds randomly placed withing the bounding box of the data.
vtkm::Bounds bounds = ds.GetCoordinateSystem().GetBounds();
std::vector<vtkm::Vec3f> seeds;
std::vector<vtkm::Particle> seeds;
for (int i = 0; i < numSeeds; i++)
for (vtkm::Id i = 0; i < numSeeds; i++)
{
vtkm::Vec3f p;
vtkm::Particle p;
vtkm::FloatDefault rx = (vtkm::FloatDefault)rand() / (vtkm::FloatDefault)RAND_MAX;
vtkm::FloatDefault ry = (vtkm::FloatDefault)rand() / (vtkm::FloatDefault)RAND_MAX;
vtkm::FloatDefault rz = (vtkm::FloatDefault)rand() / (vtkm::FloatDefault)RAND_MAX;
p[0] = static_cast<vtkm::FloatDefault>(bounds.X.Min + rx * bounds.X.Length());
p[1] = static_cast<vtkm::FloatDefault>(bounds.Y.Min + ry * bounds.Y.Length());
p[2] = static_cast<vtkm::FloatDefault>(bounds.Z.Min + rz * bounds.Z.Length());
p.Pos[0] = static_cast<vtkm::FloatDefault>(bounds.X.Min + rx * bounds.X.Length());
p.Pos[1] = static_cast<vtkm::FloatDefault>(bounds.Y.Min + ry * bounds.Y.Length());
p.Pos[2] = static_cast<vtkm::FloatDefault>(bounds.Z.Min + rz * bounds.Z.Length());
p.ID = i;
seeds.push_back(p);
}
vtkm::cont::ArrayHandle<vtkm::Vec3f> seedArray = vtkm::cont::make_ArrayHandle(seeds);
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
//compute streamlines
vtkm::filter::Streamline streamline;

@ -17,3 +17,6 @@ target_link_libraries(RedistributePoints PRIVATE vtkm_filter)
vtkm_add_target_information(RedistributePoints
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES RedistributePoints.cxx)
set_property(TARGET RedistributePoints PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET RedistributePoints PROPERTY CXX_VISIBILITY_PRESET "hidden")

@ -70,8 +70,21 @@ int main(int argc, char** argv)
vtkm::cont::DataSet ds2 = reader2.ReadDataSet();
// Use the coordinate system as seeds for performing advection
vtkm::cont::ArrayHandle<vtkm::Vec3f> seeds;
vtkm::cont::ArrayCopy(ds1.GetCoordinateSystem().GetData(), seeds);
vtkm::cont::ArrayHandle<vtkm::Vec3f> pts;
vtkm::cont::ArrayCopy(ds1.GetCoordinateSystem().GetData(), pts);
vtkm::cont::ArrayHandle<vtkm::Particle> seeds;
vtkm::Id numPts = pts.GetNumberOfValues();
seeds.Allocate(numPts);
auto ptsPortal = pts.ReadPortal();
auto seedPortal = seeds.ReadPortal();
for (vtkm::Id i = 0; i < numPts; i++)
{
vtkm::Particle p;
p.Pos = ptsPortal.Get(i);
p.ID = i;
seedPortal.Set(i, p);
}
// Instantiate the filter by providing necessary parameters.
// Necessary parameters are :

191
vtkm/Algorithms.h Normal file

@ -0,0 +1,191 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_Algorithms_h
#define vtk_m_Algorithms_h
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/BinaryPredicates.h>
#include <vtkm/internal/Configure.h>
#include <algorithm>
#include <iterator>
namespace vtkm
{
/// Similar to std::lower_bound and std::upper_bound, but returns an iterator
/// to any matching item (rather than a specific one). Returns @a last when
/// @a val is not found.
/// @{
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val, Comp comp)
{
auto len = last - first;
while (len != 0)
{
const auto halfLen = len / 2;
IterT mid = first + halfLen;
if (comp(*mid, val))
{
first = mid + 1;
len -= halfLen + 1;
}
else if (comp(val, *mid))
{
len = halfLen;
}
else
{
return mid; // found element
}
}
return last; // did not find element
}
template <typename IterT, typename T>
VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val)
{
return vtkm::BinarySearch(first, last, val, vtkm::SortLess{});
}
/// @}
/// Similar to std::lower_bound and std::upper_bound, but returns the index of
/// any matching item (rather than a specific one). Returns -1 when @a val is not
/// found.
/// @{
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val, Comp comp)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::BinarySearch(first, last, val, comp);
return result == last ? static_cast<vtkm::Id>(-1) : static_cast<vtkm::Id>(result - first);
}
// Return -1 if not found
template <typename PortalT, typename T>
VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::BinarySearch(first, last, val, vtkm::SortLess{});
return result == last ? static_cast<vtkm::Id>(-1) : static_cast<vtkm::Id>(result - first);
}
/// @}
/// Implementation of std::lower_bound or std::upper_bound that is appropriate
/// for both control and execution environments.
/// The overloads that take portals return indices instead of iterators.
/// @{
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val, Comp comp)
{
#ifdef VTKM_CUDA
auto len = last - first;
while (len != 0)
{
const auto halfLen = len / 2;
IterT mid = first + halfLen;
if (comp(*mid, val))
{
first = mid + 1;
len -= halfLen + 1;
}
else
{
len = halfLen;
}
}
return first;
#else // VTKM_CUDA
return std::lower_bound(first, last, val, std::move(comp));
#endif // VTKM_CUDA
}
template <typename IterT, typename T>
VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val)
{
return vtkm::LowerBound(first, last, val, vtkm::SortLess{});
}
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val, Comp comp)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::LowerBound(first, last, val, comp);
return static_cast<vtkm::Id>(result - first);
}
template <typename PortalT, typename T>
VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::LowerBound(first, last, val, vtkm::SortLess{});
return static_cast<vtkm::Id>(result - first);
}
template <typename IterT, typename T, typename Comp>
VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val, Comp comp)
{
#ifdef VTKM_CUDA
auto len = last - first;
while (len != 0)
{
const auto halfLen = len / 2;
IterT mid = first + halfLen;
if (!comp(val, *mid))
{
first = mid + 1;
len -= halfLen + 1;
}
else
{
len = halfLen;
}
}
return first;
#else // VTKM_CUDA
return std::upper_bound(first, last, val, std::move(comp));
#endif // VTKM_CUDA
}
template <typename IterT, typename T>
VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val)
{
return vtkm::UpperBound(first, last, val, vtkm::SortLess{});
}
template <typename PortalT, typename T, typename Comp>
VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val, Comp comp)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::UpperBound(first, last, val, comp);
return static_cast<vtkm::Id>(result - first);
}
template <typename PortalT, typename T>
VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val)
{
auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal);
auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal);
auto result = vtkm::UpperBound(first, last, val, vtkm::SortLess{});
return static_cast<vtkm::Id>(result - first);
}
/// @}
} // end namespace vtkm
#endif // vtk_m_Algorithms_h

@ -13,7 +13,7 @@
#include <vtkm/internal/Configure.h>
#include <assert.h>
#include <cassert>
/// \def VTKM_ASSERT(condition)
///
@ -34,6 +34,7 @@
#elif !defined(NDEBUG) && !defined(VTKM_NO_ASSERT)
//Only assert if we are in debug mode and don't have VTKM_NO_ASSERT defined
#define VTKM_ASSERT(condition) assert(condition)
#define VTKM_ASSERTS_CHECKED
#else
#define VTKM_ASSERT(condition) (void)(condition)
#endif

@ -29,26 +29,48 @@ namespace vtkm
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns sum (addition) of the two values.
/// Note: Requires Type \p T implement the + operator.
/// @note Requires a suitable definition of `operator+(T, U)`.
struct Sum
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT auto operator()(const T& x, const U& y) const -> decltype(x + y)
{
return x + y;
}
// If both types are the same integral type, explicitly cast the result to
// type T to avoid narrowing conversion warnings from operations that promote
// to int (e.g. `int operator+(char, char)`)
template <typename T>
VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(const T& x, const T& y) const
{
return static_cast<T>(x + y);
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns product (multiplication) of the two values.
/// Note: Requires Type \p T implement the * operator.
/// @note Requires a suitable definition of `operator*(T, U)`.
struct Product
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT auto operator()(const T& x, const U& y) const -> decltype(x * y)
{
return x * y;
}
// If both types are the same integral type, explicitly cast the result to
// type T to avoid narrowing conversion warnings from operations that promote
// to int (e.g. `int operator+(char, char)`)
template <typename T>
VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(const T& x, const T& y) const
{
return static_cast<T>(x * y);
}
};
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
@ -57,12 +79,13 @@ struct Product
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns the \c x if x > y otherwise returns \c y.
/// Note: Requires Type \p T implement the < operator.
/// @note Requires a suitable definition of `bool operator<(T, U)` and that
/// `T` and `U` share a common type.
//needs to be full length to not clash with vtkm::math function Max.
struct Maximum
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT typename std::common_type<T, U>::type operator()(const T& x, const U& y) const
{
return x < y ? y : x;
}
@ -70,19 +93,20 @@ struct Maximum
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns the \c x if x < y otherwise returns \c y.
/// Note: Requires Type \p T implement the < operator.
/// @note Requires a suitable definition of `bool operator<(T, U)` and that
/// `T` and `U` share a common type.
//needs to be full length to not clash with vtkm::math function Min.
struct Minimum
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT typename std::common_type<T, U>::type operator()(const T& x, const U& y) const
{
return x < y ? x : y;
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns a vtkm::Vec<T,2> that represents the minimum and maximum values
/// returns a vtkm::Vec<T,2> that represents the minimum and maximum values.
/// Note: Requires Type \p T implement the vtkm::Min and vtkm::Max functions.
template <typename T>
struct MinAndMax
@ -117,38 +141,71 @@ struct MinAndMax
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns the bitwise operation <tt>x&y</tt>
/// Note: Requires Type \p T implement the & operator.
/// @note Requires a suitable definition of `operator&(T, U)`.
struct BitwiseAnd
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT auto operator()(const T& x, const U& y) const -> decltype(x & y)
{
return x & y;
}
// If both types are the same integral type, explicitly cast the result to
// type T to avoid narrowing conversion warnings from operations that promote
// to int (e.g. `int operator+(char, char)`)
template <typename T>
VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(const T& x, const T& y) const
{
return static_cast<T>(x & y);
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns the bitwise operation <tt>x|y</tt>
/// Note: Requires Type \p T implement the | operator.
/// @note Requires a suitable definition of `operator&(T, U)`.
struct BitwiseOr
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT auto operator()(const T& x, const U& y) const -> decltype(x | y)
{
return x | y;
}
// If both types are the same integral type, explicitly cast the result to
// type T to avoid narrowing conversion warnings from operations that promote
// to int (e.g. `int operator+(char, char)`)
template <typename T>
VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(const T& x, const T& y) const
{
return static_cast<T>(x | y);
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns the bitwise operation <tt>x^y</tt>
/// Note: Requires Type \p T implement the ^ operator.
/// @note Requires a suitable definition of `operator&(T, U)`.
struct BitwiseXor
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT auto operator()(const T& x, const U& y) const -> decltype(x ^ y)
{
return x ^ y;
}
// If both types are the same integral type, explicitly cast the result to
// type T to avoid narrowing conversion warnings from operations that promote
// to int (e.g. `int operator+(char, char)`)
template <typename T>
VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(const T& x, const T& y) const
{
return static_cast<T>(x ^ y);
}
};
} // namespace vtkm

@ -15,37 +15,37 @@
namespace vtkm
{
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x is equal to \c y.
/// Note: Requires Type \p T implement the == operator.
struct Equal
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
{
return x == y;
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x is not equal to \c y.
/// Note: Requires Type \p T implement the != operator.
/// @note: Requires that types T and U are comparable with !=.
struct NotEqual
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return x != y;
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x is equal to \c y.
/// @note: Requires that types T and U are comparable with !=.
struct Equal
{
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return x == y;
}
};
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x is less than \c y.
/// Note: Requires Type \p T implement the < operator.
/// @note: Requires that types T and U are comparable with <.
struct SortLess
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return x < y;
}
@ -53,12 +53,12 @@ struct SortLess
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x is greater than \c y.
/// Note: Requires Type \p T implement the < operator, as we invert the
/// comparison
/// @note: Requires that types T and U are comparable via operator<(U, T).
struct SortGreater
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return y < x;
}
@ -66,12 +66,12 @@ struct SortGreater
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x and \c y are True.
/// Note: Requires Type \p T to be convertible to \c bool or implement the
/// && operator.
/// @note: Requires that types T and U are comparable with &&.
struct LogicalAnd
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return x && y;
}
@ -79,12 +79,11 @@ struct LogicalAnd
/// Binary Predicate that takes two arguments argument \c x, and \c y and
/// returns True if and only if \c x or \c y is True.
/// Note: Requires Type \p T to be convertible to \c bool or implement the
/// || operator.
/// @note: Requires that types T and U are comparable with ||.
struct LogicalOr
{
template <typename T>
VTKM_EXEC_CONT bool operator()(const T& x, const T& y) const
template <typename T, typename U>
VTKM_EXEC_CONT bool operator()(const T& x, const U& y) const
{
return x || y;
}

@ -11,7 +11,7 @@
#ifndef vtk_m_Bitset_h
#define vtk_m_Bitset_h
#include <assert.h>
#include <cassert>
#include <limits>
#include <vtkm/Types.h>
#include <vtkm/internal/ExportMacros.h>
@ -22,18 +22,27 @@ namespace vtkm
/// \brief A bitmap to serve different needs.
/// Ex. Editing particular bits in a byte(s), checkint if particular bit values
/// are present or not. Once Cuda supports std::bitset, we should use the
/// standard one if possible
/// standard one if possible. Additional cast in logical operations are required
/// to avoid compiler warnings when using 16 or 8 bit MaskType.
template <typename MaskType>
struct Bitset
{
VTKM_EXEC_CONT void set(vtkm::Id bitIndex)
{
this->Mask = this->Mask | (static_cast<MaskType>(1) << bitIndex);
this->Mask = static_cast<MaskType>(this->Mask | (static_cast<MaskType>(1) << bitIndex));
}
VTKM_EXEC_CONT void set(vtkm::Id bitIndex, bool val)
{
if (val)
this->set(bitIndex);
else
this->reset(bitIndex);
}
VTKM_EXEC_CONT void reset(vtkm::Id bitIndex)
{
this->Mask = this->Mask & ~(static_cast<MaskType>(1) << bitIndex);
this->Mask = static_cast<MaskType>(this->Mask & ~(static_cast<MaskType>(1) << bitIndex));
}
VTKM_EXEC_CONT void toggle(vtkm::Id bitIndex)
@ -41,7 +50,7 @@ struct Bitset
this->Mask = this->Mask ^ (static_cast<MaskType>(0) << bitIndex);
}
VTKM_EXEC_CONT bool test(vtkm::Id bitIndex)
VTKM_EXEC_CONT bool test(vtkm::Id bitIndex) const
{
return ((this->Mask & (static_cast<MaskType>(1) << bitIndex)) != 0);
}

@ -17,6 +17,7 @@ vtkm_install_headers(
vtkm ${VTKm_BINARY_INCLUDE_DIR}/${kit_dir}/Version.h)
set(headers
Algorithms.h
Assert.h
BinaryPredicates.h
BinaryOperators.h
@ -25,15 +26,18 @@ set(headers
CellClassification.h
CellShape.h
CellTraits.h
Deprecated.h
Flags.h
Geometry.h
Hash.h
ImplicitFunction.h
List.h
ListTag.h
Math.h
Matrix.h
NewtonsMethod.h
Pair.h
Particle.h
Range.h
RangeId.h
RangeId2.h
@ -42,6 +46,7 @@ set(headers
Swap.h
TopologyElementTag.h
Transform3D.h
TypeList.h
TypeListTag.h
Types.h
TypeTraits.h

142
vtkm/Deprecated.h Normal file

@ -0,0 +1,142 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_Deprecated_h
#define vtk_m_Deprecated_h
#include <vtkm/StaticAssert.h>
#include <vtkm/Types.h>
#define VTK_M_DEPRECATED_MAKE_MESSAGE(...) \
VTKM_EXPAND(VTK_M_DEPRECATED_MAKE_MESSAGE_IMPL(__VA_ARGS__, "", vtkm::internal::NullType{}))
#define VTK_M_DEPRECATED_MAKE_MESSAGE_IMPL(version, message, ...) \
message " Deprecated in version " #version "."
/// \def VTKM_DEPRECATED(version, message)
///
/// Classes and methods are marked deprecated using the `VTKM_DEPRECATED`
/// macro. The first argument of `VTKM_DEPRECATED` should be set to the first
/// version in which the feature is deprecated. For example, if the last
/// released version of VTK-m was 1.5, and on the master branch a developer
/// wants to deprecate a class foo, then the `VTKM_DEPRECATED` release version
/// should be given as 1.6, which will be the next minor release of VTK-m. The
/// second argument of `VTKM_DEPRECATED`, which is optional but highly
/// encouraged, is a short message that should clue developers on how to update
/// their code to the new changes. For example, it could point to the
/// replacement class or method for the changed feature.
///
/// \def VTKM_DEPRECATED_SUPPRESS_BEGIN
///
/// Begins a region of code in which warnings about using deprecated code are ignored.
/// Such suppression is usually helpful when implementing other deprecated features.
/// (You would think if one deprecated method used another deprecated method this
/// would not be a warning, but it is.)
///
/// Any use of `VTKM_DEPRECATED_SUPPRESS_BEGIN` must be paired with a
/// `VTKM_DEPRECATED_SUPPRESS_END`, which will re-enable warnings in subsequent code.
///
/// Do not use a semicolon after this macro.
///
/// \def VTKM_DEPRECATED_SUPPRESS_END
///
/// Ends a region of code in which warnings about using deprecated code are ignored.
/// Any use of `VTKM_DEPRECATED_SUPPRESS_BEGIN` must be paired with a
/// `VTKM_DEPRECATED_SUPPRESS_END`.
///
/// Do not use a semicolon after this macro.
///
// Determine whether the [[deprecated]] attribute is supported. Note that we are not
// using other older compiler features such as __attribute__((__deprecated__)) because
// they do not all support all [[deprecated]] uses (such as uses in enums). If
// [[deprecated]] is supported, then VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED will get defined.
#ifndef VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#if __cplusplus >= 201402L
// C++14 and better supports [[deprecated]]
// Except in these cases:
// - nvcc on visual studio
#if !(defined(VTKM_MSVC) && defined(VTKM_CUDA))
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif
#elif defined(VTKM_GCC)
// GCC has supported [[deprecated]] since version 5.0, but using it on enum was not
// supported until 6.0. So we have to make a special case to only use it for high
// enough revisions.
#if __GNUC__ >= 6
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif // Too old GCC
#elif defined(__has_cpp_attribute)
#if __has_cpp_attribute(deprecated)
// Compiler not fully C++14 compliant, but it reports to support [[deprecated]]
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif // __has_cpp_attribute(deprecated)
#elif defined(VTKM_MSVC) && (_MSC_VER >= 1900) && !defined(VTKM_CUDA)
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif // no known compiler support for [[deprecated]]
#endif // VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED check
// Determine how to turn deprecated warnings on and off, generally with pragmas. If
// deprecated warnings can be turned off and on, then VTK_M_DEPRECATED_SUPPRESS_SUPPORTED
// is defined and the pair VTKM_DEPRECATED_SUPPRESS_BEGIN and VTKM_DEPRECATED_SUPRESS_END
// are defined to the pragmas to disable and restore these warnings. If this support
// cannot be determined, VTK_M_DEPRECATED_SUPPRESS_SUPPORTED is _not_ define whereas
// VTKM_DEPRECATED_SUPPRESS_BEGIN and VTKM_DEPRECATED_SUPPRESS_END are defined to be
// empty.
#ifndef VTKM_DEPRECATED_SUPPRESS_SUPPORTED
#if defined(VTKM_GCC) || defined(VTKM_CLANG)
#define VTKM_DEPRECATED_SUPPRESS_SUPPORTED
#define VTKM_DEPRECATED_SUPPRESS_BEGIN \
_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#define VTKM_DEPRECATED_SUPPRESS_END _Pragma("GCC diagnostic pop")
#elif defined(VTKM_MSVC)
#define VTKM_DEPRECATED_SUPPRESS_SUPPORTED
#define VTKM_DEPRECATED_SUPPRESS_BEGIN __pragma(warning(push)) __pragma(warning(disable : 4996))
#define VTKM_DEPRECATED_SUPPRESS_END __pragma(warning(pop))
#else
// Other compilers probably have different pragmas for turning warnings off and on.
// Adding more compilers to this list is fine, but the above probably capture most
// developers and should be covered on dashboards.
#define VTKM_DEPRECATED_SUPPRESS_BEGIN
#define VTKM_DEPRECATED_SUPPRESS_END
#endif
#endif // VTKM_DEPRECATED_SUPPRESS_SUPPORTED check
#if !defined(VTKM_DEPRECATED_SUPPRESS_BEGIN) || !defined(VTKM_DEPRECATED_SUPPRESS_END)
#error VTKM_DEPRECATED_SUPPRESS macros not properly defined.
#endif
// Only actually use the [[deprecated]] attribute if the compiler supports it AND
// we know how to suppress deprecations when necessary.
#if defined(VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED) && defined(VTKM_DEPRECATED_SUPPRESS_SUPPORTED)
#define VTKM_DEPRECATED(...) [[deprecated(VTK_M_DEPRECATED_MAKE_MESSAGE(__VA_ARGS__))]]
#else
#define VTKM_DEPRECATED(...)
#endif
#endif // vtk_m_Deprecated_h

586
vtkm/List.h Normal file

@ -0,0 +1,586 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_List_h
#define vtk_m_List_h
#include <vtkm/Types.h>
#include <vtkm/internal/brigand.hpp>
namespace vtkm
{
template <typename... Ts>
struct List
{
};
namespace detail
{
// This prototype is here to detect deprecated ListTag objects. When ListTags are removed, then
// this should be removed too.
struct ListRoot;
}
namespace internal
{
template <typename T>
struct IsListImpl
{
// This prototype is here to detect deprecated ListTag objects. When ListTags are removed, then
// this should be changed to be just std::false_type.
using type = std::is_base_of<vtkm::detail::ListRoot, T>;
};
template <typename... Ts>
struct IsListImpl<vtkm::List<Ts...>>
{
using type = std::true_type;
};
template <typename T>
using IsList = typename vtkm::internal::IsListImpl<T>::type;
} // namespace internal
/// Checks that the argument is a proper list. This is a handy concept
/// check for functions and classes to make sure that a template argument is
/// actually a device adapter tag. (You can get weird errors elsewhere in the
/// code when a mistake is made.)
///
#define VTKM_IS_LIST(type) \
VTKM_STATIC_ASSERT_MSG((::vtkm::internal::IsList<type>::value), \
"Provided type is not a valid VTK-m list type.")
namespace detail
{
/// list value that is used to represent a list actually matches all values
struct UniversalTypeTag
{
//We never want this tag constructed, and by deleting the constructor
//we get an error when trying to use this class with ForEach.
UniversalTypeTag() = delete;
};
} // namespace detail
namespace internal
{
// This is here so that the old (deprecated) `ListTag`s can convert themselves to the new
// `List` style and be operated on. When that deprecated functionality goes away, we can
// probably remove `AsList` and just operate directly on the `List`s.
template <typename T>
struct AsListImpl;
template <typename... Ts>
struct AsListImpl<vtkm::List<Ts...>>
{
using type = vtkm::List<Ts...>;
};
template <typename T>
using AsList = typename AsListImpl<T>::type;
}
/// A special tag for an empty list.
///
using ListEmpty = vtkm::List<>;
/// A special tag for a list that represents holding all potential values
///
/// Note: Can not be used with ForEach and some list transforms for obvious reasons.
using ListUniversal = vtkm::List<detail::UniversalTypeTag>;
namespace detail
{
template <typename T, template <typename...> class Target>
struct ListApplyImpl;
template <typename... Ts, template <typename...> class Target>
struct ListApplyImpl<vtkm::List<Ts...>, Target>
{
using type = Target<Ts...>;
};
// Cannot apply the universal list.
template <template <typename...> class Target>
struct ListApplyImpl<vtkm::ListUniversal, Target>;
} // namespace detail
/// \brief Applies the list of types to a template.
///
/// Given a ListTag and a templated class, returns the class instantiated with the types
/// represented by the ListTag.
///
template <typename List, template <typename...> class Target>
using ListApply = typename detail::ListApplyImpl<internal::AsList<List>, Target>::type;
/// Becomes an std::integral_constant containing the number of types in a list.
///
template <typename List>
using ListSize =
std::integral_constant<vtkm::IdComponent,
vtkm::IdComponent{ brigand::size<internal::AsList<List>>::value }>;
/// \brief Finds the type at the given index.
///
/// This becomes the type of the list at the given index.
///
template <typename List, vtkm::IdComponent Index>
using ListAt =
brigand::at<internal::AsList<List>, std::integral_constant<vtkm::IdComponent, Index>>;
namespace detail
{
// This find is roughly based on the brigand::find functionality. We don't use brigand::find
// because it has an apparent bug where if a list contains templated types, it trys to
// apply those types as predicates, which is wrong.
template <vtkm::IdComponent NumSearched, typename Target, typename... Remaining>
struct FindFirstOfType;
// Not found
template <vtkm::IdComponent NumSearched, typename Target>
struct FindFirstOfType<NumSearched, Target> : std::integral_constant<vtkm::IdComponent, -1>
{
};
// Basic search next one
template <bool NextIsTarget, vtkm::IdComponent NumSearched, typename Target, typename... Remaining>
struct FindFirstOfCheckHead;
template <vtkm::IdComponent NumSearched, typename Target, typename... Ts>
struct FindFirstOfCheckHead<true, NumSearched, Target, Ts...>
: std::integral_constant<vtkm::IdComponent, NumSearched>
{
};
template <vtkm::IdComponent NumSearched, typename Target, typename Next, typename... Remaining>
struct FindFirstOfCheckHead<false, NumSearched, Target, Next, Remaining...>
: FindFirstOfCheckHead<std::is_same<Target, Next>::value, NumSearched + 1, Target, Remaining...>
{
};
// Not found
template <vtkm::IdComponent NumSearched, typename Target>
struct FindFirstOfCheckHead<false, NumSearched, Target>
: std::integral_constant<vtkm::IdComponent, -1>
{
};
template <vtkm::IdComponent NumSearched, typename Target, typename Next, typename... Remaining>
struct FindFirstOfType<NumSearched, Target, Next, Remaining...>
: FindFirstOfCheckHead<std::is_same<Target, Next>::value, NumSearched, Target, Remaining...>
{
};
// If there are at least 6 entries, check the first 4 to quickly narrow down
template <bool OneInFirst4Matches, vtkm::IdComponent NumSearched, typename Target, typename... Ts>
struct FindFirstOfSplit4;
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename... Ts>
struct FindFirstOfSplit4<true, NumSearched, Target, T0, T1, T2, T3, Ts...>
: FindFirstOfCheckHead<std::is_same<Target, T0>::value, NumSearched, Target, T1, T2, T3>
{
};
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename T4,
typename... Ts>
struct FindFirstOfSplit4<false, NumSearched, Target, T0, T1, T2, T3, T4, Ts...>
: FindFirstOfCheckHead<std::is_same<Target, T4>::value, NumSearched + 4, Target, Ts...>
{
};
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename... Ts>
struct FindFirstOfType<NumSearched, Target, T0, T1, T2, T3, T4, T5, Ts...>
: FindFirstOfSplit4<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
std::is_same<Target, T2>::value ||
std::is_same<Target, T3>::value),
NumSearched,
Target,
T0,
T1,
T2,
T3,
T4,
T5,
Ts...>
{
};
// If there are at least 12 entries, check the first 8 to quickly narrow down
template <bool OneInFirst8Matches, vtkm::IdComponent NumSearched, typename Target, typename... Ts>
struct FindFirstOfSplit8;
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename... Ts>
struct FindFirstOfSplit8<true, NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, Ts...>
: FindFirstOfSplit4<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
std::is_same<Target, T2>::value ||
std::is_same<Target, T3>::value),
NumSearched,
Target,
T0,
T1,
T2,
T3,
T4,
T5,
T6,
T7>
{
};
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename... Ts>
struct FindFirstOfSplit8<false, NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, Ts...>
: FindFirstOfType<NumSearched + 8, Target, Ts...>
{
};
template <vtkm::IdComponent NumSearched,
typename Target,
typename T0,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8,
typename T9,
typename T10,
typename T11,
typename... Ts>
struct FindFirstOfType<NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, Ts...>
: FindFirstOfSplit8<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
std::is_same<Target, T2>::value ||
std::is_same<Target, T3>::value ||
std::is_same<Target, T4>::value ||
std::is_same<Target, T5>::value ||
std::is_same<Target, T6>::value ||
std::is_same<Target, T7>::value),
NumSearched,
Target,
T0,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
Ts...>
{
};
template <typename List, typename Target>
struct ListIndexOfImpl;
template <typename... Ts, typename Target>
struct ListIndexOfImpl<vtkm::List<Ts...>, Target>
{
using type = std::integral_constant<vtkm::IdComponent, FindFirstOfType<0, Target, Ts...>::value>;
};
template <typename Target>
struct ListIndexOfImpl<vtkm::ListUniversal, Target>
{
VTKM_STATIC_ASSERT_MSG((std::is_same<Target, void>::value && std::is_same<Target, int>::value),
"Cannot get indices in a universal list.");
};
} // namespace detail
/// \brief Finds the index of a given type.
///
/// Becomes a `std::integral_constant` for the index of the given type. If the
/// given type is not in the list, the value is set to -1.
///
template <typename List, typename T>
using ListIndexOf = typename detail::ListIndexOfImpl<internal::AsList<List>, T>::type;
namespace detail
{
template <typename List, typename T>
struct ListHasImpl
{
using type = std::integral_constant<bool, (vtkm::ListIndexOf<List, T>::value >= 0)>;
};
template <typename T>
struct ListHasImpl<vtkm::ListUniversal, T>
{
using type = std::true_type;
};
} // namespace detail
/// \brief Checks to see if the given `T` is in the list pointed to by `List`.
///
/// Becomes `std::true_type` if the `T` is in `List`. `std::false_type` otherwise.
///
template <typename List, typename T>
using ListHas = typename detail::ListHasImpl<internal::AsList<List>, T>::type;
#if defined(VTKM_MSVC) && (_MSC_VER < 1911)
// Alternate definition of ListAppend to get around an apparent issue with
// Visual Studio 2015.
namespace detail
{
template <typename... Lists>
struct ListAppendImpl
{
using type = brigand::append<internal::AsList<Lists>...>;
};
} // namespace detail
template <typename... Lists>
using ListAppend = typename detail::ListAppendImpl<Lists...>::type;
#else // Normal definition
/// Concatinates a set of lists into a single list.
///
/// Note that this does not work correctly with `vtkm::ListUniversal`.
template <typename... Lists>
using ListAppend = brigand::append<internal::AsList<Lists>...>;
#endif
namespace detail
{
template <bool Has, typename State, typename Element>
struct ListIntersectTagsChoose;
template <typename State, typename Element>
struct ListIntersectTagsChoose<true, State, Element>
{
using type = brigand::push_back<State, Element>;
};
template <typename State, typename Element>
struct ListIntersectTagsChoose<false, State, Element>
{
using type = State;
};
template <class State, class Element, class List>
struct ListIntersectTags
: ListIntersectTagsChoose<vtkm::ListHas<List, Element>::value, State, Element>
{
};
template <typename List1, typename List2>
struct ListIntersectImpl
{
VTKM_IS_LIST(List1);
VTKM_IS_LIST(List2);
using type =
brigand::fold<List1,
vtkm::List<>,
ListIntersectTags<brigand::_state, brigand::_element, brigand::pin<List2>>>;
};
template <typename List1>
struct ListIntersectImpl<List1, vtkm::ListUniversal>
{
VTKM_IS_LIST(List1);
using type = List1;
};
template <typename List2>
struct ListIntersectImpl<vtkm::ListUniversal, List2>
{
VTKM_IS_LIST(List2);
using type = List2;
};
template <>
struct ListIntersectImpl<vtkm::ListUniversal, vtkm::ListUniversal>
{
using type = vtkm::ListUniversal;
};
} // namespace detail
/// Constructs a list containing types present in all lists.
///
template <typename List1, typename List2>
using ListIntersect =
typename detail::ListIntersectImpl<internal::AsList<List1>, internal::AsList<List2>>::type;
namespace detail
{
template <typename T, template <typename> class Target>
struct ListTransformImpl;
template <typename... Ts, template <typename> class Target>
struct ListTransformImpl<vtkm::List<Ts...>, Target>
{
using type = vtkm::List<Target<Ts>...>;
};
// Cannot transform the universal list.
template <template <typename> class Target>
struct ListTransformImpl<vtkm::ListUniversal, Target>;
} // namespace detail
/// Constructs a list containing all types in a source list applied to a transform template.
///
template <typename List, template <typename> class Transform>
using ListTransform = typename detail::ListTransformImpl<internal::AsList<List>, Transform>::type;
/// Takes an existing `List` and a predicate template that is applied to each type in the `List`.
/// Any type in the `List` that has a value element equal to true (the equivalent of
/// `std::true_type`), that item will be removed from the list. For example the following type
///
/// ```cpp
/// vtkm::ListRemoveIf<vtkm::List<int, float, long long, double>, std::is_integral>
/// ```
///
/// resolves to a `List` that is equivalent to `vtkm::List<float, double>` because
/// `std::is_integral<int>` and `std::is_integral<long long>` resolve to `std::true_type` whereas
/// `std::is_integral<float>` and `std::is_integral<double>` resolve to `std::false_type`.
///
template <typename List, template <typename> class Predicate>
using ListRemoveIf =
brigand::remove_if<internal::AsList<List>, brigand::bind<Predicate, brigand::_1>>;
namespace detail
{
// We want to use an initializer list as a trick to call a function once for each type, but
// an initializer list needs a type, so create wrapper function that returns a value.
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Functor, typename... Args>
VTKM_EXEC_CONT inline bool ListForEachCallThrough(Functor&& f, Args&&... args)
{
f(std::forward<Args>(args)...);
return false; // Return value does not matter. Hopefully just thrown away.
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Functor, typename... Ts, typename... Args>
VTKM_EXEC_CONT void ListForEachImpl(Functor&& f, vtkm::List<Ts...>, Args&&... args)
{
auto init_list = { ListForEachCallThrough(
std::forward<Functor>(f), Ts{}, std::forward<Args>(args)...)... };
(void)init_list;
}
template <typename Functor, typename... Args>
VTKM_EXEC_CONT void ListForEachImpl(Functor&&, vtkm::ListEmpty, Args&&...)
{
// No types to run functor on.
}
} // namespace detail
/// For each typename represented by the list, call the functor with a
/// default instance of that type.
///
template <typename Functor, typename List, typename... Args>
VTKM_EXEC_CONT void ListForEach(Functor&& f, List, Args&&... args)
{
detail::ListForEachImpl(
std::forward<Functor>(f), internal::AsList<List>{}, std::forward<Args>(args)...);
}
namespace detail
{
template <typename List1, typename List2>
struct ListCrossImpl
{
VTKM_IS_LIST(List1);
VTKM_IS_LIST(List2);
// This is a lazy Cartesian product generator.
// This version was settled on as being the best default
// version as all compilers including Intel handle this
// implementation without issue for very large cross products
using type = brigand::reverse_fold<
vtkm::List<List1, List2>,
vtkm::List<vtkm::List<>>,
brigand::lazy::join<brigand::lazy::transform<
brigand::_2,
brigand::defer<brigand::lazy::join<brigand::lazy::transform<
brigand::parent<brigand::_1>,
brigand::defer<brigand::bind<
vtkm::List,
brigand::lazy::push_front<brigand::_1, brigand::parent<brigand::_1>>>>>>>>>>;
};
} // namespace detail
/// \brief Generates a list that is the cross product of two input lists.
///
/// The resulting list has the form of `vtkm::List<vtkm::List<A1,B1>, vtkm::List<A1,B2>,...>`
///
template <typename List1, typename List2>
using ListCross =
typename detail::ListCrossImpl<internal::AsList<List1>, internal::AsList<List2>>::type;
} // namespace vtkm
#endif //vtk_m_List_h

@ -10,15 +10,63 @@
#ifndef vtk_m_ListTag_h
#define vtk_m_ListTag_h
#include <vtkm/internal/ListTagDetail.h>
#include <vtkm/Deprecated.h>
#include <vtkm/List.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/internal/ExportMacros.h>
#include <vtkm/internal/brigand.hpp>
#include <type_traits>
namespace vtkm
{
namespace detail
{
//-----------------------------------------------------------------------------
/// Base class that all ListTag classes inherit from. Helps identify lists
/// in macros like VTKM_IS_LIST_TAG.
///
struct ListRoot
{
};
template <class... T>
using ListBase = brigand::list<T...>;
/// list value that is used to represent a list actually matches all values
struct UniversalTag
{
//We never want this tag constructed, and by deleting the constructor
//we get an error when trying to use this class with ForEach.
UniversalTag() = delete;
};
} // namespace detail
//-----------------------------------------------------------------------------
/// A basic tag for a list of typenames. This struct can be subclassed
/// and still behave like a list tag.
template <typename... ArgTypes>
struct VTKM_DEPRECATED(1.6, "ListTagBase replace by List. Note that List cannot be subclassed.")
ListTagBase : detail::ListRoot
{
using list = detail::ListBase<ArgTypes...>;
};
/// A special tag for a list that represents holding all potential values
///
/// Note: Can not be used with ForEach for obvious reasons.
struct VTKM_DEPRECATED(
1.6,
"ListTagUniversal replaced by ListUniversal. Note that ListUniversal cannot be subclassed.")
ListTagUniversal : detail::ListRoot
{
using list = vtkm::detail::ListBase<vtkm::detail::UniversalTag>;
};
namespace internal
{
@ -31,13 +79,24 @@ struct ListTagCheck : std::is_base_of<vtkm::detail::ListRoot, ListTag>
} // namespace internal
namespace detail
{
template <typename ListTag>
struct VTKM_DEPRECATED(1.6, "VTKM_IS_LIST_TAG replaced with VTKM_IS_LIST.") ListTagAssert
: internal::IsList<ListTag>
{
};
} // namespace detal
/// Checks that the argument is a proper list tag. This is a handy concept
/// check for functions and classes to make sure that a template argument is
/// actually a device adapter tag. (You can get weird errors elsewhere in the
/// code when a mistake is made.)
///
#define VTKM_IS_LIST_TAG(tag) \
VTKM_STATIC_ASSERT_MSG((::vtkm::internal::ListTagCheck<tag>::value), \
VTKM_STATIC_ASSERT_MSG((::vtkm::detail::ListTagAssert<tag>::value), \
"Provided type is not a valid VTK-m list tag.")
namespace internal
@ -49,8 +108,10 @@ namespace detail
template <typename ListTag>
struct ListTagAsBrigandListImpl
{
VTKM_DEPRECATED_SUPPRESS_BEGIN
VTKM_IS_LIST_TAG(ListTag);
using type = typename ListTag::list;
VTKM_DEPRECATED_SUPPRESS_END
};
} // namespace detail
@ -60,6 +121,38 @@ struct ListTagAsBrigandListImpl
template <typename ListTag>
using ListTagAsBrigandList = typename detail::ListTagAsBrigandListImpl<ListTag>::type;
VTKM_DEPRECATED_SUPPRESS_BEGIN
namespace detail
{
// Could use ListApply instead, but that causes deprecation warnings.
template <typename List>
struct ListAsListTagImpl;
template <typename... Ts>
struct ListAsListTagImpl<vtkm::List<Ts...>>
{
using type = vtkm::ListTagBase<Ts...>;
};
} // namespace detail
template <typename List>
using ListAsListTag = typename detail::ListAsListTagImpl<List>::type;
VTKM_DEPRECATED_SUPPRESS_END
// This allows the new `List` operations work on `ListTag`s.
template <typename T>
struct AsListImpl
{
VTKM_STATIC_ASSERT_MSG(ListTagCheck<T>::value,
"Attempted to use something that is not a List with a List operation.");
VTKM_DEPRECATED_SUPPRESS_BEGIN
using type = typename std::conditional<std::is_base_of<vtkm::ListTagUniversal, T>::value,
vtkm::ListUniversal,
brigand::wrap<ListTagAsBrigandList<T>, vtkm::List>>::type;
VTKM_DEPRECATED_SUPPRESS_END
};
} // namespace internal
@ -83,20 +176,15 @@ struct ListTagApplyImpl<brigand::list<Ts...>, Target>
/// represented by the ListTag.
///
template <typename ListTag, template <typename...> class Target>
using ListTagApply =
using ListTagApply VTKM_DEPRECATED(1.6, "ListTagApply replaced by ListApply.") =
typename detail::ListTagApplyImpl<internal::ListTagAsBrigandList<ListTag>, Target>::type;
/// A special tag for a list that represents holding all potential values
///
/// Note: Can not be used with ForEach for obvious reasons.
struct ListTagUniversal : detail::ListRoot
{
using list = vtkm::detail::ListBase<vtkm::detail::UniversalTag>;
};
/// A special tag for an empty list.
///
struct ListTagEmpty : detail::ListRoot
struct VTKM_DEPRECATED(
1.6,
"ListTagEmpty replaced by ListEmpty. Note that ListEmpty cannot be subclassed.") ListTagEmpty
: detail::ListRoot
{
using list = vtkm::detail::ListBase<>;
};
@ -104,87 +192,95 @@ struct ListTagEmpty : detail::ListRoot
/// A tag that is a construction of two other tags joined together. This struct
/// can be subclassed and still behave like a list tag.
template <typename... ListTags>
struct ListTagJoin : detail::ListRoot
struct VTKM_DEPRECATED(
1.6,
"ListTagJoin replaced by ListAppend. Note that ListAppend cannot be subclassed.") ListTagJoin
: vtkm::internal::ListAsListTag<vtkm::ListAppend<ListTags...>>
{
using list = typename detail::ListJoin<internal::ListTagAsBrigandList<ListTags>...>::type;
};
/// A tag that is constructed by appending \c Type to \c ListTag.
template <typename ListTag, typename Type>
struct ListTagAppend : detail::ListRoot
struct VTKM_DEPRECATED(1.6,
"ListTagAppend<List, Type> replaced by ListAppend<List, vtkm::List<Type>. "
"Note that ListAppend cannot be subclassed.") ListTagAppend
: vtkm::internal::ListAsListTag<vtkm::ListAppend<ListTag, vtkm::List<Type>>>
{
VTKM_IS_LIST_TAG(ListTag);
using list = typename detail::ListJoin<internal::ListTagAsBrigandList<ListTag>,
detail::ListBase<Type>>::type;
};
/// Append \c Type to \c ListTag only if \c ListTag does not already contain \c Type.
/// No checks are performed to see if \c ListTag itself has only unique elements.
template <typename ListTag, typename Type>
struct ListTagAppendUnique : detail::ListRoot
struct VTKM_DEPRECATED(1.6) ListTagAppendUnique
: std::conditional<
vtkm::ListHas<ListTag, Type>::value,
vtkm::internal::ListAsListTag<vtkm::internal::AsList<ListTag>>,
vtkm::internal::ListAsListTag<vtkm::ListAppend<ListTag, vtkm::List<Type>>>>::type
{
VTKM_IS_LIST_TAG(ListTag);
using list =
typename detail::ListAppendUniqueImpl<internal::ListTagAsBrigandList<ListTag>, Type>::type;
};
/// A tag that consists of elements that are found in both tags. This struct
/// can be subclassed and still behave like a list tag.
template <typename ListTag1, typename ListTag2>
struct ListTagIntersect : detail::ListRoot
struct VTKM_DEPRECATED(
1.6,
"ListTagIntersect replaced by ListIntersect. Note that ListIntersect cannot be subclassed.")
ListTagIntersect : vtkm::internal::ListAsListTag<vtkm::ListIntersect<ListTag1, ListTag2>>
{
VTKM_IS_LIST_TAG(ListTag1);
VTKM_IS_LIST_TAG(ListTag2);
using list = typename detail::ListIntersect<internal::ListTagAsBrigandList<ListTag1>,
internal::ListTagAsBrigandList<ListTag2>>::type;
};
/// A list tag that consists of each item in another list tag fed into a template that takes
/// a single parameter.
template <typename ListTag, template <typename> class Transform>
struct ListTagTransform : detail::ListRoot
struct VTKM_DEPRECATED(
1.6,
"ListTagTransform replaced by ListTransform. Note that ListTransform cannot be subclassed.")
ListTagTransform : vtkm::internal::ListAsListTag<vtkm::ListTransform<ListTag, Transform>>
{
VTKM_IS_LIST_TAG(ListTag);
using list = brigand::transform<internal::ListTagAsBrigandList<ListTag>,
brigand::bind<Transform, brigand::_1>>;
};
/// \brief Determines the number of types in the given list.
/// A list tag that takes an existing ListTag and a predicate template that is applied to
/// each type in the ListTag. Any type in the ListTag that has a value element equal to true
/// (the equivalent of std::true_type), that item will be removed from the list. For example
/// the following type
///
/// There is a static member named \c value that is set to the length of the list.
/// ```cpp
/// vtkm::ListTagRemoveIf<vtkm::ListTagBase<int, float, long long, double>, std::is_integral>
/// ```
///
template <typename ListTag>
struct ListSize
/// resolves to a ListTag that is equivalent to `vtkm::ListTag<float, double>` because
/// `std::is_integral<int>` and `std::is_integral<long long>` resolve to `std::true_type`
/// whereas `std::is_integral<float>` and `std::is_integral<double>` resolve to
/// `std::false_type`.
template <typename ListTag, template <typename> class Predicate>
struct VTKM_DEPRECATED(
1.6,
"ListTagRemoveIf replaced by ListRemoveIf. Note that ListRemoveIf cannot be subclassed.")
ListTagRemoveIf : vtkm::internal::ListAsListTag<vtkm::ListRemoveIf<ListTag, Predicate>>
{
VTKM_IS_LIST_TAG(ListTag);
static constexpr vtkm::IdComponent value =
detail::ListSizeImpl<internal::ListTagAsBrigandList<ListTag>>::value;
};
/// For each typename represented by the list tag, call the functor with a
/// default instance of that type.
///
template <typename Functor, typename ListTag, typename... Args>
VTKM_CONT void ListForEach(Functor&& f, ListTag, Args&&... args)
namespace detail
{
VTKM_IS_LIST_TAG(ListTag);
detail::ListForEachImpl(std::forward<Functor>(f),
internal::ListTagAsBrigandList<ListTag>{},
std::forward<Args>(args)...);
}
// Old stlye ListCrossProduct expects brigand::list instead of vtkm::List. Transform back
template <typename List>
using ListToBrigand = vtkm::ListApply<List, brigand::list>;
} // namespace detail
/// Generate a tag that is the cross product of two other tags. The resulting
/// tag has the form of Tag< brigand::list<A1,B1>, brigand::list<A1,B2> .... >
///
template <typename ListTag1, typename ListTag2>
struct ListCrossProduct : detail::ListRoot
struct VTKM_DEPRECATED(
1.6,
"ListCrossProduct replaced by ListCross. Note that LIstCross cannot be subclassed.")
ListCrossProduct
: vtkm::internal::ListAsListTag<
vtkm::ListTransform<vtkm::ListCross<ListTag1, ListTag2>, detail::ListToBrigand>>
{
VTKM_IS_LIST_TAG(ListTag1);
VTKM_IS_LIST_TAG(ListTag2);
using list =
typename detail::ListCrossProductImpl<internal::ListTagAsBrigandList<ListTag1>,
internal::ListTagAsBrigandList<ListTag2>>::type;
};
/// \brief Checks to see if the given \c Type is in the list pointed to by \c ListTag.
@ -193,11 +289,9 @@ struct ListCrossProduct : detail::ListRoot
/// contained in the list and false otherwise.
///
template <typename ListTag, typename Type>
struct ListContains
struct VTKM_DEPRECATED(1.6, "ListContains replaced by ListHas.") ListContains
: vtkm::ListHas<ListTag, Type>
{
VTKM_IS_LIST_TAG(ListTag);
static constexpr bool value =
detail::ListContainsImpl<Type, internal::ListTagAsBrigandList<ListTag>>::value;
};
/// \brief Finds the type at the given index.
@ -205,26 +299,15 @@ struct ListContains
/// This struct contains subtype \c type that resolves to the type at the given index.
///
template <typename ListTag, vtkm::IdComponent Index>
struct ListTypeAt
struct VTKM_DEPRECATED(1.6, "ListTypeAt::type replaced by ListAt.") ListTypeAt
{
VTKM_DEPRECATED_SUPPRESS_BEGIN
VTKM_IS_LIST_TAG(ListTag);
VTKM_DEPRECATED_SUPPRESS_END
using type = brigand::at<internal::ListTagAsBrigandList<ListTag>,
std::integral_constant<vtkm::IdComponent, Index>>;
};
/// \brief Finds the index of the given type.
///
/// There is a static member named \c value that is set to the index of the given type. If the
/// given type is not in the list, the value is set to -1.
///
template <typename ListTag, typename Type>
struct ListIndexOf
{
VTKM_IS_LIST_TAG(ListTag);
static constexpr vtkm::IdComponent value =
detail::ListIndexOfImpl<Type, internal::ListTagAsBrigandList<ListTag>, 0>::value;
};
} // namespace vtkm
#endif //vtk_m_ListTag_h

105
vtkm/Particle.h Normal file

@ -0,0 +1,105 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_Particle_h
#define vtk_m_Particle_h
#include <vtkm/Bitset.h>
namespace vtkm
{
//Bit field describing the status:
class ParticleStatus : public vtkm::Bitset<vtkm::UInt8>
{
public:
VTKM_EXEC_CONT ParticleStatus()
{
this->SetOk();
this->ClearTerminate();
}
VTKM_EXEC_CONT void SetOk() { this->set(this->SUCCESS_BIT); }
VTKM_EXEC_CONT bool CheckOk() const { return this->test(this->SUCCESS_BIT); }
VTKM_EXEC_CONT void SetFail() { this->reset(this->SUCCESS_BIT); }
VTKM_EXEC_CONT bool CheckFail() const { return !this->test(this->SUCCESS_BIT); }
VTKM_EXEC_CONT void SetTerminate() { this->set(this->TERMINATE_BIT); }
VTKM_EXEC_CONT void ClearTerminate() { this->reset(this->TERMINATE_BIT); }
VTKM_EXEC_CONT bool CheckTerminate() const { return this->test(this->TERMINATE_BIT); }
VTKM_EXEC_CONT void SetSpatialBounds() { this->set(this->SPATIAL_BOUNDS_BIT); }
VTKM_EXEC_CONT void ClearSpatialBounds() { this->reset(this->SPATIAL_BOUNDS_BIT); }
VTKM_EXEC_CONT bool CheckSpatialBounds() const { return this->test(this->SPATIAL_BOUNDS_BIT); }
VTKM_EXEC_CONT void SetTemporalBounds() { this->set(this->TEMPORAL_BOUNDS_BIT); }
VTKM_EXEC_CONT void ClearTemporalBounds() { this->reset(this->TEMPORAL_BOUNDS_BIT); }
VTKM_EXEC_CONT bool CheckTemporalBounds() const { return this->test(this->TEMPORAL_BOUNDS_BIT); }
VTKM_EXEC_CONT void SetTookAnySteps() { this->set(this->TOOK_ANY_STEPS_BIT); }
VTKM_EXEC_CONT void ClearTookAnySteps() { this->reset(this->TOOK_ANY_STEPS_BIT); }
VTKM_EXEC_CONT bool CheckTookAnySteps() const { return this->test(this->TOOK_ANY_STEPS_BIT); }
private:
static constexpr vtkm::Id SUCCESS_BIT = 0;
static constexpr vtkm::Id TERMINATE_BIT = 1;
static constexpr vtkm::Id SPATIAL_BOUNDS_BIT = 2;
static constexpr vtkm::Id TEMPORAL_BOUNDS_BIT = 3;
static constexpr vtkm::Id TOOK_ANY_STEPS_BIT = 4;
};
inline VTKM_CONT std::ostream& operator<<(std::ostream& s, const vtkm::ParticleStatus& status)
{
s << "[" << status.CheckOk() << " " << status.CheckTerminate() << " "
<< status.CheckSpatialBounds() << " " << status.CheckTemporalBounds() << "]";
return s;
}
class Particle
{
public:
VTKM_EXEC_CONT
Particle() {}
VTKM_EXEC_CONT
Particle(const vtkm::Vec3f& p,
const vtkm::Id& id,
const vtkm::Id& numSteps = 0,
const vtkm::ParticleStatus& status = vtkm::ParticleStatus(),
const vtkm::FloatDefault& time = 0)
: Pos(p)
, ID(id)
, NumSteps(numSteps)
, Status(status)
, Time(time)
{
}
VTKM_EXEC_CONT
Particle(const vtkm::Particle& p)
: Pos(p.Pos)
, ID(p.ID)
, NumSteps(p.NumSteps)
, Status(p.Status)
, Time(p.Time)
{
}
vtkm::Particle& operator=(const vtkm::Particle& p) = default;
vtkm::Vec3f Pos;
vtkm::Id ID = -1;
vtkm::Id NumSteps = 0;
vtkm::ParticleStatus Status;
vtkm::FloatDefault Time = 0;
};
}
#endif // vtk_m_Particle_h

@ -177,7 +177,7 @@ inline VTKM_CONT std::ostream& operator<<(std::ostream& stream, const vtkm::Rang
{
return stream << "[" << range.Min << ".." << range.Max << "]";
} // Declared inside of vtkm namespace so that the operator work with ADL lookup
} // namespace vtkm
#endif //vtk_m_Range_h

@ -131,13 +131,12 @@ struct RangeId
}
};
} // namespace vtkm
/// Helper function for printing ranges during testing
///
static inline VTKM_CONT std::ostream& operator<<(std::ostream& stream, const vtkm::RangeId& range)
{
return stream << "[" << range.Min << ".." << range.Max << ")";
}
} // Declared inside of vtkm namespace so that the operator work with ADL lookup
} // namespace vtkm
#endif // vtk_m_RangeId_h

@ -142,6 +142,32 @@ struct RangeId2
{
return ((this->X != range.X) || (this->Y != range.Y));
}
VTKM_EXEC_CONT
vtkm::RangeId& operator[](IdComponent c) noexcept
{
if (c <= 0)
{
return this->X;
}
else
{
return this->Y;
}
}
VTKM_EXEC_CONT
const vtkm::RangeId& operator[](IdComponent c) const noexcept
{
if (c <= 0)
{
return this->X;
}
else
{
return this->Y;
}
}
};
} // namespace vtkm

@ -158,15 +158,47 @@ struct RangeId3
{
return ((this->X != range.X) || (this->Y != range.Y) || (this->Z != range.Z));
}
};
VTKM_EXEC_CONT
vtkm::RangeId& operator[](IdComponent c) noexcept
{
if (c <= 0)
{
return this->X;
}
else if (c == 1)
{
return this->Y;
}
else
{
return this->Z;
}
}
} // namespace vtkm
VTKM_EXEC_CONT
const vtkm::RangeId& operator[](IdComponent c) const noexcept
{
if (c <= 0)
{
return this->X;
}
else if (c == 1)
{
return this->Y;
}
else
{
return this->Z;
}
}
};
/// Helper function for printing range during testing
///
static inline VTKM_CONT std::ostream& operator<<(std::ostream& stream, const vtkm::RangeId3& range)
inline VTKM_CONT std::ostream& operator<<(std::ostream& stream, const vtkm::RangeId3& range)
{
return stream << "{ X:" << range.X << ", Y:" << range.Y << ", Z:" << range.Z << " }";
}
} // Declared inside of vtkm namespace so that the operator work with ADL lookup
} // namespace vtkm
#endif //vtk_m_RangeId3_h

@ -10,8 +10,8 @@
#ifndef vtk_m_StaticAssert_h
#define vtk_m_StaticAssert_h
#include <type_traits>
#include <vtkm/internal/Configure.h>
#define VTKM_STATIC_ASSERT(condition) \
static_assert((condition), "Failed static assert: " #condition)

176
vtkm/TypeList.h Normal file

@ -0,0 +1,176 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_TypeList_h
#define vtk_m_TypeList_h
#ifndef VTKM_DEFAULT_TYPE_LIST
#define VTKM_DEFAULT_TYPE_LIST ::vtkm::TypeListCommon
#endif
#include <vtkm/List.h>
#include <vtkm/Types.h>
namespace vtkm
{
/// A list containing the type vtkm::Id.
///
using TypeListId = vtkm::List<vtkm::Id>;
/// A list containing the type vtkm::Id2.
///
using TypeListId2 = vtkm::List<vtkm::Id2>;
/// A list containing the type vtkm::Id3.
///
using TypeListId3 = vtkm::List<vtkm::Id3>;
/// A list containing the type vtkm::Id4.
///
using TypeListId4 = vtkm::List<vtkm::Id4>;
/// A list containing the type vtkm::IdComponent
///
using TypeListIdComponent = vtkm::List<vtkm::IdComponent>;
/// A list containing types used to index arrays. Contains vtkm::Id, vtkm::Id2,
/// and vtkm::Id3.
///
using TypeListIndex = vtkm::List<vtkm::Id, vtkm::Id2, vtkm::Id3>;
/// A list containing types used for scalar fields. Specifically, contains
/// floating point numbers of different widths (i.e. vtkm::Float32 and
/// vtkm::Float64).
using TypeListFieldScalar = vtkm::List<vtkm::Float32, vtkm::Float64>;
/// A list containing types for values for fields with two dimensional
/// vectors.
///
using TypeListFieldVec2 = vtkm::List<vtkm::Vec2f_32, vtkm::Vec2f_64>;
/// A list containing types for values for fields with three dimensional
/// vectors.
///
using TypeListFieldVec3 = vtkm::List<vtkm::Vec3f_32, vtkm::Vec3f_64>;
/// A list containing types for values for fields with four dimensional
/// vectors.
///
using TypeListFieldVec4 = vtkm::List<vtkm::Vec4f_32, vtkm::Vec4f_64>;
/// A list containing common types for floating-point vectors. Specifically contains
/// floating point vectors of size 2, 3, and 4 with floating point components.
/// Scalars are not included.
///
using TypeListFloatVec = vtkm::List<vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>;
/// A list containing common types for values in fields. Specifically contains
/// floating point scalars and vectors of size 2, 3, and 4 with floating point
/// components.
///
using TypeListField = vtkm::List<vtkm::Float32,
vtkm::Float64,
vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>;
/// A list of all scalars defined in vtkm/Types.h. A scalar is a type that
/// holds a single number.
///
using TypeListScalarAll = vtkm::List<vtkm::Int8,
vtkm::UInt8,
vtkm::Int16,
vtkm::UInt16,
vtkm::Int32,
vtkm::UInt32,
vtkm::Int64,
vtkm::UInt64,
vtkm::Float32,
vtkm::Float64>;
/// A list of the most commonly use Vec classes. Specifically, these are
/// vectors of size 2, 3, or 4 containing either unsigned bytes, signed
/// integers of 32 or 64 bits, or floating point values of 32 or 64 bits.
///
using TypeListVecCommon = vtkm::List<vtkm::Vec2ui_8,
vtkm::Vec2i_32,
vtkm::Vec2i_64,
vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3ui_8,
vtkm::Vec3i_32,
vtkm::Vec3i_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4ui_8,
vtkm::Vec4i_32,
vtkm::Vec4i_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>;
namespace internal
{
/// A list of uncommon Vec classes with length up to 4. This is not much
/// use in general, but is used when joined with \c TypeListVecCommon
/// to get a list of all vectors up to size 4.
///
using TypeListVecUncommon = vtkm::List<vtkm::Vec2i_8,
vtkm::Vec2i_16,
vtkm::Vec2ui_16,
vtkm::Vec2ui_32,
vtkm::Vec2ui_64,
vtkm::Vec3i_8,
vtkm::Vec3i_16,
vtkm::Vec3ui_16,
vtkm::Vec3ui_32,
vtkm::Vec3ui_64,
vtkm::Vec4i_8,
vtkm::Vec4i_16,
vtkm::Vec4ui_16,
vtkm::Vec4ui_32,
vtkm::Vec4ui_64>;
} // namespace internal
/// A list of all vector classes with standard types as components and
/// lengths between 2 and 4.
///
using TypeListVecAll =
vtkm::ListAppend<vtkm::TypeListVecCommon, vtkm::internal::TypeListVecUncommon>;
/// A list of all basic types listed in vtkm/Types.h. Does not include all
/// possible VTK-m types like arbitrarily typed and sized Vecs (only up to
/// length 4) or math types like matrices.
///
using TypeListAll = vtkm::ListAppend<vtkm::TypeListScalarAll, vtkm::TypeListVecAll>;
/// A list of the most commonly used types across multiple domains. Includes
/// integers, floating points, and 3 dimensional vectors of floating points.
///
using TypeListCommon = vtkm::List<vtkm::UInt8,
vtkm::Int32,
vtkm::Int64,
vtkm::Float32,
vtkm::Float64,
vtkm::Vec3f_32,
vtkm::Vec3f_64>;
} // namespace vtkm
#endif //vtk_m_TypeList_h

@ -10,207 +10,65 @@
#ifndef vtk_m_TypeListTag_h
#define vtk_m_TypeListTag_h
// Everything in this header file is deprecated and movded to TypeList.h.
#ifndef VTKM_DEFAULT_TYPE_LIST_TAG
#define VTKM_DEFAULT_TYPE_LIST_TAG ::vtkm::TypeListTagCommon
#define VTKM_DEFAULT_TYPE_LIST_TAG ::vtkm::internal::TypeListTagDefault
#endif
#include <vtkm/ListTag.h>
#include <vtkm/Types.h>
#include <vtkm/TypeList.h>
#define VTK_M_OLD_TYPE_LIST_DEFINITION(name) \
struct VTKM_ALWAYS_EXPORT \
VTKM_DEPRECATED( \
1.6, \
"TypeListTag" #name " replaced by TypeList" #name ". " \
"Note that the new TypeList" #name " cannot be subclassed.") \
TypeListTag ## name : vtkm::internal::ListAsListTag<TypeList ## name> \
{ \
}
VTKM_DEPRECATED_SUPPRESS_BEGIN
namespace vtkm
{
/// A list containing the type vtkm::Id.
///
struct VTKM_ALWAYS_EXPORT TypeListTagId : vtkm::ListTagBase<vtkm::Id>
{
};
/// A list containing the type vtkm::Id2.
///
struct VTKM_ALWAYS_EXPORT TypeListTagId2 : vtkm::ListTagBase<vtkm::Id2>
{
};
/// A list containing the type vtkm::Id3.
///
struct VTKM_ALWAYS_EXPORT TypeListTagId3 : vtkm::ListTagBase<vtkm::Id3>
{
};
/// A list containing the type vtkm::IdComponent
///
struct VTKM_ALWAYS_EXPORT TypeListTagIdComponent : vtkm::ListTagBase<vtkm::IdComponent>
{
};
/// A list containing types used to index arrays. Contains vtkm::Id, vtkm::Id2,
/// and vtkm::Id3.
///
struct VTKM_ALWAYS_EXPORT TypeListTagIndex : vtkm::ListTagBase<vtkm::Id, vtkm::Id2, vtkm::Id3>
{
};
/// A list containing types used for scalar fields. Specifically, contains
/// floating point numbers of different widths (i.e. vtkm::Float32 and
/// vtkm::Float64).
struct VTKM_ALWAYS_EXPORT TypeListTagFieldScalar : vtkm::ListTagBase<vtkm::Float32, vtkm::Float64>
{
};
/// A list containing types for values for fields with two dimensional
/// vectors.
///
struct VTKM_ALWAYS_EXPORT TypeListTagFieldVec2
: vtkm::ListTagBase<vtkm::Vec2f_32, vtkm::Vec2f_64>
{
};
/// A list containing types for values for fields with three dimensional
/// vectors.
///
struct VTKM_ALWAYS_EXPORT TypeListTagFieldVec3
: vtkm::ListTagBase<vtkm::Vec3f_32, vtkm::Vec3f_64>
{
};
/// A list containing types for values for fields with four dimensional
/// vectors.
///
struct VTKM_ALWAYS_EXPORT TypeListTagFieldVec4
: vtkm::ListTagBase<vtkm::Vec4f_32, vtkm::Vec4f_64>
{
};
/// A list containing common types for floating-point vectors. Specifically contains
/// floating point vectors of size 2, 3, and 4 with floating point components.
/// Scalars are not included.
///
struct VTKM_ALWAYS_EXPORT TypeListTagFloatVec
: vtkm::ListTagBase<vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>
{
};
/// A list containing common types for values in fields. Specifically contains
/// floating point scalars and vectors of size 2, 3, and 4 with floating point
/// components.
///
struct VTKM_ALWAYS_EXPORT TypeListTagField
: vtkm::ListTagBase<vtkm::Float32,
vtkm::Float64,
vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>
{
};
/// A list of all scalars defined in vtkm/Types.h. A scalar is a type that
/// holds a single number.
///
struct VTKM_ALWAYS_EXPORT TypeListTagScalarAll
: vtkm::ListTagBase<vtkm::Int8,
vtkm::UInt8,
vtkm::Int16,
vtkm::UInt16,
vtkm::Int32,
vtkm::UInt32,
vtkm::Int64,
vtkm::UInt64,
vtkm::Float32,
vtkm::Float64>
{
};
/// A list of the most commonly use Vec classes. Specifically, these are
/// vectors of size 2, 3, or 4 containing either unsigned bytes, signed
/// integers of 32 or 64 bits, or floating point values of 32 or 64 bits.
///
struct VTKM_ALWAYS_EXPORT TypeListTagVecCommon
: vtkm::ListTagBase<vtkm::Vec2ui_8,
vtkm::Vec2i_32,
vtkm::Vec2i_64,
vtkm::Vec2f_32,
vtkm::Vec2f_64,
vtkm::Vec3ui_8,
vtkm::Vec3i_32,
vtkm::Vec3i_64,
vtkm::Vec3f_32,
vtkm::Vec3f_64,
vtkm::Vec4ui_8,
vtkm::Vec4i_32,
vtkm::Vec4i_64,
vtkm::Vec4f_32,
vtkm::Vec4f_64>
{
};
VTK_M_OLD_TYPE_LIST_DEFINITION(Id);
VTK_M_OLD_TYPE_LIST_DEFINITION(Id2);
VTK_M_OLD_TYPE_LIST_DEFINITION(Id3);
VTK_M_OLD_TYPE_LIST_DEFINITION(IdComponent);
VTK_M_OLD_TYPE_LIST_DEFINITION(Index);
VTK_M_OLD_TYPE_LIST_DEFINITION(FieldScalar);
VTK_M_OLD_TYPE_LIST_DEFINITION(FieldVec2);
VTK_M_OLD_TYPE_LIST_DEFINITION(FieldVec3);
VTK_M_OLD_TYPE_LIST_DEFINITION(FieldVec4);
VTK_M_OLD_TYPE_LIST_DEFINITION(FloatVec);
VTK_M_OLD_TYPE_LIST_DEFINITION(Field);
VTK_M_OLD_TYPE_LIST_DEFINITION(ScalarAll);
VTK_M_OLD_TYPE_LIST_DEFINITION(VecCommon);
VTK_M_OLD_TYPE_LIST_DEFINITION(VecAll);
VTK_M_OLD_TYPE_LIST_DEFINITION(All);
VTK_M_OLD_TYPE_LIST_DEFINITION(Common);
namespace internal
{
/// A list of uncommon Vec classes with length up to 4. This is not much
/// use in general, but is used when joined with \c TypeListTagVecCommon
/// to get a list of all vectors up to size 4.
///
struct VTKM_ALWAYS_EXPORT TypeListTagVecUncommon
: vtkm::ListTagBase<vtkm::Vec2i_8,
vtkm::Vec2i_16,
vtkm::Vec2ui_16,
vtkm::Vec2ui_32,
vtkm::Vec2ui_64,
vtkm::Vec3i_8,
vtkm::Vec3i_16,
vtkm::Vec3ui_16,
vtkm::Vec3ui_32,
vtkm::Vec3ui_64,
vtkm::Vec4i_8,
vtkm::Vec4i_16,
vtkm::Vec4ui_16,
vtkm::Vec4ui_32,
vtkm::Vec4ui_64>
VTK_M_OLD_TYPE_LIST_DEFINITION(VecUncommon);
// Special definition of TypeListTagCommon to give descriptive warning when
// VTKM_DEFAULT_TYPE_LIST_TAG is used.
struct VTKM_ALWAYS_EXPORT
VTKM_DEPRECATED(
1.6,
"VTKM_DEFAULT_TYPE_LIST_TAG replaced by VTKM_DEFAULT_TYPE_LIST. "
"Note that the new VTKM_DEFAULT_TYPE_LIST cannot be subclassed.")
TypeListTagDefault : vtkm::internal::ListAsListTag<VTKM_DEFAULT_TYPE_LIST>
{
};
} // namespace internal
/// A list of all vector classes with standard types as components and
/// lengths between 2 and 4.
///
struct VTKM_ALWAYS_EXPORT TypeListTagVecAll
: vtkm::ListTagJoin<vtkm::TypeListTagVecCommon, vtkm::internal::TypeListTagVecUncommon>
{
};
/// A list of all basic types listed in vtkm/Types.h. Does not include all
/// possible VTK-m types like arbitrarily typed and sized Vecs (only up to
/// length 4) or math types like matrices.
///
struct VTKM_ALWAYS_EXPORT TypeListTagAll
: vtkm::ListTagJoin<vtkm::TypeListTagScalarAll, vtkm::TypeListTagVecAll>
{
};
/// A list of the most commonly used types across multiple domains. Includes
/// integers, floating points, and 3 dimensional vectors of floating points.
///
struct VTKM_ALWAYS_EXPORT TypeListTagCommon
: vtkm::ListTagBase<vtkm::UInt8,
vtkm::Int32,
vtkm::Int64,
vtkm::Float32,
vtkm::Float64,
vtkm::Vec3f_32,
vtkm::Vec3f_64>
{
};
// Special implementation of ListContains for TypeListTagAll to always be
// true. Although TypeListTagAll is necessarily finite, the point is to
// be all inclusive. Besides, this should speed up the compilation when
@ -221,6 +79,24 @@ struct ListContains<vtkm::TypeListTagAll, Type>
static constexpr bool value = true;
};
// Special implementation of ListHas for TypeListTagAll to always be
// true. Although TypeListTagAll is necessarily finite, the point is to
// be all inclusive. Besides, this should speed up the compilation when
// checking a list that should contain everything.
namespace detail
{
template<typename Type>
struct ListHasImpl<vtkm::TypeListTagAll, Type>
{
using type = std::true_type;
};
} // namespace detail
} // namespace vtkm
VTKM_DEPRECATED_SUPPRESS_END
#undef VTK_M_OLD_TYPE_LIST_DEFINITION
#endif //vtk_m_TypeListTag_h

@ -16,6 +16,7 @@
#include <vtkm/Assert.h>
#include <vtkm/StaticAssert.h>
#include <cstdint>
#include <iostream>
#include <type_traits>
@ -152,12 +153,12 @@ namespace vtkm
//*****************************************************************************
using Float32 = float;
using Float64 = double;
using Int8 = signed char;
using UInt8 = unsigned char;
using Int16 = short;
using UInt16 = unsigned short;
using Int32 = int;
using UInt32 = unsigned int;
using Int8 = int8_t;
using UInt8 = uint8_t;
using Int16 = int16_t;
using UInt16 = uint16_t;
using Int32 = int32_t;
using UInt32 = uint32_t;
/// Represents a component ID (index of component in a vector). The number
/// of components, being a value fixed at compile time, is generally assumed

@ -14,6 +14,7 @@
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/cont/Token.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/internal/ArrayManagerExecution.h>
@ -26,15 +27,15 @@ namespace cont
namespace detail
{
template <typename Device, typename T>
inline auto DoPrepareArgForExec(T&& object, std::true_type)
-> decltype(std::declval<T>().PrepareForExecution(Device()))
inline auto DoPrepareArgForExec(T&& object, vtkm::cont::Token& token, std::true_type) -> decltype(
vtkm::cont::internal::CallPrepareForExecution(std::forward<T>(object), Device{}, token))
{
VTKM_IS_EXECUTION_OBJECT(T);
return object.PrepareForExecution(Device{});
return vtkm::cont::internal::CallPrepareForExecution(std::forward<T>(object), Device{}, token);
}
template <typename Device, typename T>
inline T&& DoPrepareArgForExec(T&& object, std::false_type)
inline T&& DoPrepareArgForExec(T&& object, vtkm::cont::Token&, std::false_type)
{
static_assert(!vtkm::cont::internal::IsExecutionObjectBase<T>::value,
"Internal error: failed to detect execution object.");
@ -42,12 +43,13 @@ inline T&& DoPrepareArgForExec(T&& object, std::false_type)
}
template <typename Device, typename T>
auto PrepareArgForExec(T&& object)
auto PrepareArgForExec(T&& object, vtkm::cont::Token& token)
-> decltype(DoPrepareArgForExec<Device>(std::forward<T>(object),
token,
vtkm::cont::internal::IsExecutionObjectBase<T>{}))
{
return DoPrepareArgForExec<Device>(std::forward<T>(object),
vtkm::cont::internal::IsExecutionObjectBase<T>{});
return DoPrepareArgForExec<Device>(
std::forward<T>(object), token, vtkm::cont::internal::IsExecutionObjectBase<T>{});
}
struct BitFieldToUnorderedSetFunctor
@ -58,8 +60,9 @@ struct BitFieldToUnorderedSetFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
this->Result = vtkm::cont::DeviceAdapterAlgorithm<Device>::BitFieldToUnorderedSet(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -70,8 +73,9 @@ struct CopyFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Copy(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -83,8 +87,9 @@ struct CopyIfFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -102,8 +107,9 @@ struct CopySubRangeFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
valid = vtkm::cont::DeviceAdapterAlgorithm<Device>::CopySubRange(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -115,8 +121,10 @@ struct CountSetBitsFunctor
template <typename Device, typename... Args>
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
this->PopCount = vtkm::cont::DeviceAdapterAlgorithm<Device>::CountSetBits(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -126,8 +134,10 @@ struct FillFunctor
template <typename Device, typename... Args>
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Fill(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -139,8 +149,9 @@ struct LowerBoundsFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::LowerBounds(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -159,8 +170,9 @@ struct ReduceFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
result = vtkm::cont::DeviceAdapterAlgorithm<Device>::Reduce(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -171,8 +183,9 @@ struct ReduceByKeyFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::ReduceByKey(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -191,8 +204,9 @@ struct ScanInclusiveResultFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
result = vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanInclusive(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -275,8 +289,9 @@ struct ScanInclusiveByKeyFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanInclusiveByKey(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -295,8 +310,9 @@ struct ScanExclusiveFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
result = vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanExclusive(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -309,8 +325,9 @@ struct ScanExclusiveByKeyFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanExclusiveByKey(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -322,8 +339,9 @@ struct ScanExtendedFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanExtended(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -334,8 +352,9 @@ struct ScheduleFunctor
VTKM_CONT bool operator()(Device, Args&&... args)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -346,8 +365,9 @@ struct SortFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Sort(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -358,8 +378,9 @@ struct SortByKeyFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::SortByKey(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -381,8 +402,9 @@ struct TransformFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Transform(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -393,8 +415,9 @@ struct UniqueFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Unique(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};
@ -405,8 +428,9 @@ struct UpperBoundsFunctor
VTKM_CONT bool operator()(Device, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::UpperBounds(
PrepareArgForExec<Device>(std::forward<Args>(args))...);
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
};

@ -35,8 +35,8 @@ namespace cont
///
/// These functions should not be called repeatedly in a loop to fetch all
/// values from an array handle. The much more efficient way to do this is to
/// use the proper control-side portals (ArrayHandle::GetPortalControl() and
/// ArrayHandle::GetPortalConstControl()).
/// use the proper control-side portals (ArrayHandle::WritePortal() and
/// ArrayHandle::ReadPortal()).
///
/// This method will attempt to copy the data using the device that the input
/// data is already valid on. If the input data is only valid in the control
@ -111,10 +111,10 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle<vtkm::Id, SIds>& ids
{ // Fallback to a control-side copy if the device copy fails or if the device
// is undefined:
const vtkm::Id numVals = ids.GetNumberOfValues();
auto idPortal = ids.GetPortalConstControl();
auto dataPortal = data.GetPortalConstControl();
auto idPortal = ids.ReadPortal();
auto dataPortal = data.ReadPortal();
output.Allocate(numVals);
auto outPortal = output.GetPortalControl();
auto outPortal = output.WritePortal();
for (vtkm::Id i = 0; i < numVals; ++i)
{
outPortal.Set(i, dataPortal.Get(idPortal.Get(i)));

@ -13,6 +13,7 @@
#include <vtkm/cont/vtkm_cont_export.h>
#include <vtkm/Assert.h>
#include <vtkm/Deprecated.h>
#include <vtkm/Flags.h>
#include <vtkm/Types.h>
@ -23,16 +24,19 @@
#include <vtkm/cont/Serialization.h>
#include <vtkm/cont/Storage.h>
#include <vtkm/cont/StorageBasic.h>
#include <vtkm/cont/Token.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <mutex>
#include <vector>
#include <vtkm/cont/internal/ArrayHandleExecutionManager.h>
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
#include <vtkm/cont/internal/ArrayPortalToken.h>
namespace vtkm
{
@ -57,24 +61,18 @@ class VTKM_CONT_EXPORT ArrayHandleBase
/// with C++11 type_traits.
///
template <typename T, typename StorageTag>
struct IsValidArrayHandle
: std::integral_constant<bool,
!(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>
{
};
using IsValidArrayHandle =
std::integral_constant<bool,
!(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>;
/// Checks to see if the given type and storage forms a invalid array handle
/// (some storage objects cannot support all types). This check is compatible
/// with C++11 type_traits.
///
template <typename T, typename StorageTag>
struct IsInValidArrayHandle
: std::integral_constant<bool,
(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>
{
};
using IsInValidArrayHandle =
std::integral_constant<bool, !IsValidArrayHandle<T, StorageTag>::value>;
/// Checks to see if the ArrayHandle allows writing, as some ArrayHandles
/// (Implicit) don't support writing. These will be defined as either
@ -84,7 +82,7 @@ struct IsInValidArrayHandle
///
template <typename ArrayHandle>
using IsWritableArrayHandle =
vtkm::internal::PortalSupportsSets<typename std::decay<ArrayHandle>::type::PortalControl>;
vtkm::internal::PortalSupportsSets<typename std::decay<ArrayHandle>::type::WritePortalType>;
/// @}
/// Checks to see if the given object is an array handle. This check is
@ -257,12 +255,16 @@ private:
using ExecutionManagerType =
vtkm::cont::internal::ArrayHandleExecutionManagerBase<T, StorageTag_>;
using MutexType = std::mutex;
using LockType = std::unique_lock<MutexType>;
public:
using StorageType = vtkm::cont::internal::Storage<T, StorageTag_>;
using ValueType = T;
using StorageTag = StorageTag_;
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
using WritePortalType = vtkm::cont::internal::ArrayPortalToken<typename StorageType::PortalType>;
using ReadPortalType =
vtkm::cont::internal::ArrayPortalToken<typename StorageType::PortalConstType>;
template <typename DeviceAdapterTag>
struct ExecutionTypes
{
@ -271,6 +273,11 @@ public:
typename ExecutionManagerType::template ExecutionTypes<DeviceAdapterTag>::PortalConst;
};
using PortalControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::WritePortalType instead.") =
typename StorageType::PortalType;
using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::ReadPortalType instead.") =
typename StorageType::PortalConstType;
/// Constructs an empty ArrayHandle. Typically used for output or
/// intermediate arrays that will be filled by a VTKm algorithm.
///
@ -367,17 +374,70 @@ public:
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
VTKM_CONT PortalControl GetPortalControl();
/// \deprecated Use `WritePortal` instead. Note that the portal returned from `WritePortal`
/// will disallow any other reads or writes to the array while it is in scope.
///
VTKM_CONT
VTKM_DEPRECATED(1.6,
"Use ArrayHandle::WritePortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
typename StorageType::PortalType GetPortalControl();
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
VTKM_CONT PortalConstControl GetPortalConstControl() const;
/// \deprecated Use `ReadPortal` instead. Note that the portal returned from `ReadPortal`
/// will disallow any writes to the array while it is in scope.
///
VTKM_CONT
VTKM_DEPRECATED(1.6,
"Use ArrayHandle::ReadPortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
typename StorageType::PortalConstType GetPortalConstControl() const;
/// \brief Get an array portal that can be used in the control environment.
///
/// The returned array can be used in the control environment to read values from the array. (It
/// is not possible to write to the returned portal. That is `Get` will work on the portal, but
/// `Set` will not.)
///
/// **Note:** The returned portal will prevent any writes or modifications to the array. To
/// ensure that the data pointed to by the portal is valid, this `ArrayHandle` will be locked to
/// any modifications while the portal remains in scope. (You can call `Detach` on the returned
/// portal to unlock the array. However, this will invalidate the portal.)
///
/// **Note:** The returned portal cannot be used in the execution environment. This is because
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
/// execution environment, use `PrepareForInput`.
///
VTKM_CONT ReadPortalType ReadPortal() const;
/// \brief Get an array portal that can be used in the control environment.
///
/// The returned array can be used in the control environment to reand and write values to the
/// array.
///
/// **Note:** The returned portal will prevent any reads, writes, or modifications to the array.
/// To ensure that the data pointed to by the portal is valid, this `ArrayHandle` will be locked
/// to any modifications while the portal remains in scope. Also, to make sure that no reads get
/// out of sync, reads other than the returned portal are also blocked. (You can call `Detach` on
/// the returned portal to unlock the array. However, this will invalidate the portal.)
///
/// **Note:** The returned portal cannot be used in the execution environment. This is because
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
/// execution environment, use `PrepareForInput`.
///
VTKM_CONT WritePortalType WritePortal() const;
/// Returns the number of entries in the array.
///
VTKM_CONT vtkm::Id GetNumberOfValues() const;
VTKM_CONT vtkm::Id GetNumberOfValues() const
{
LockType lock = this->GetLock();
return this->GetNumberOfValues(lock);
}
/// \brief Allocates an array large enough to hold the given number of values.
///
@ -390,9 +450,11 @@ public:
VTKM_CONT
void Allocate(vtkm::Id numberOfValues)
{
this->ReleaseResourcesExecutionInternal();
this->Internals->ControlArray.Allocate(numberOfValues);
this->Internals->ControlArrayValid = true;
LockType lock = this->GetLock();
this->WaitToWrite(lock, vtkm::cont::Token{});
this->ReleaseResourcesExecutionInternal(lock);
this->Internals->GetControlArray(lock)->Allocate(numberOfValues);
this->Internals->SetControlArrayValid(lock, true);
}
/// \brief Reduces the size of the array without changing its values.
@ -410,37 +472,48 @@ public:
///
VTKM_CONT void ReleaseResourcesExecution()
{
LockType lock = this->GetLock();
this->WaitToWrite(lock, vtkm::cont::Token{});
// Save any data in the execution environment by making sure it is synced
// with the control environment.
this->SyncControlArray();
this->SyncControlArray(lock);
this->ReleaseResourcesExecutionInternal();
this->ReleaseResourcesExecutionInternal(lock);
}
/// Releases all resources in both the control and execution environments.
///
VTKM_CONT void ReleaseResources()
{
this->ReleaseResourcesExecutionInternal();
LockType lock = this->GetLock();
if (this->Internals->ControlArrayValid)
this->ReleaseResourcesExecutionInternal(lock);
if (this->Internals->IsControlArrayValid(lock))
{
this->Internals->ControlArray.ReleaseResources();
this->Internals->ControlArrayValid = false;
this->Internals->GetControlArray(lock)->ReleaseResources();
this->Internals->SetControlArrayValid(lock, false);
}
}
// clang-format off
/// Prepares this array to be used as an input to an operation in the
/// execution environment. If necessary, copies data to the execution
/// environment. Can throw an exception if this array does not yet contain
/// any data. Returns a portal that can be used in code running in the
/// execution environment.
///
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT
typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(DeviceAdapterTag) const;
// clang-format on
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(
DeviceAdapterTag,
vtkm::cont::Token& token) const;
/// Prepares (allocates) this array to be used as an output from an operation
/// in the execution environment. The internal state of this class is set to
@ -449,10 +522,16 @@ public:
/// called). Returns a portal that can be used in code running in the
/// execution environment.
///
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForOutput(
vtkm::Id numberOfValues,
DeviceAdapterTag);
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag, vtkm::cont::Token& token);
/// Prepares this array to be used in an in-place operation (both as input
/// and output) in the execution environment. If necessary, copies data to
@ -460,16 +539,55 @@ public:
/// yet contain any data. Returns a portal that can be used in code running
/// in the execution environment.
///
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(DeviceAdapterTag);
/// Gets this array handle ready to interact with the given device. If the
/// array handle has already interacted with this device, then this method
/// does nothing. Although the internal state of this class can change, the
/// method is declared const because logically the data does not.
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT void PrepareForDevice(DeviceAdapterTag) const;
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(
DeviceAdapterTag,
vtkm::cont::Token& token);
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(DeviceAdapterTag) const
{
vtkm::cont::Token token;
return this->PrepareForInput(DeviceAdapterTag{}, token);
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
{
vtkm::cont::Token token;
return this->PrepareForOutput(numberOfValues, DeviceAdapterTag{}, token);
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(DeviceAdapterTag)
{
vtkm::cont::Token token;
return this->PrepareForInPlace(DeviceAdapterTag{}, token);
}
/// Returns the DeviceAdapterId for the current device. If there is no device
/// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is
/// returned.
///
/// Note that in a multithreaded environment the validity of this result can
/// change.
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const
{
LockType lock = this->GetLock();
return this->Internals->IsExecutionArrayValid(lock)
? this->Internals->GetExecutionArray(lock)->GetDeviceAdapterId()
: DeviceAdapterTagUndefined{};
}
/// Synchronizes the control array with the execution array. If either the
/// user array or control array is already valid, this method does nothing
@ -477,38 +595,193 @@ public:
/// Although the internal state of this class can change, the method is
/// declared const because logically the data does not.
///
VTKM_CONT void SyncControlArray() const;
VTKM_CONT void SyncControlArray() const
{
LockType lock = this->GetLock();
this->SyncControlArray(lock);
}
// Probably should make this private, but ArrayHandleStreaming needs access.
protected:
/// Acquires a lock on the internals of this `ArrayHandle`. The calling
/// function should keep the returned lock and let it go out of scope
/// when the lock is no longer needed.
///
LockType GetLock() const { return LockType(this->Internals->Mutex); }
/// Returns true if read operations can currently be performed.
///
VTKM_CONT bool CanRead(const LockType& lock, const vtkm::cont::Token& token) const
{
return ((*this->Internals->GetWriteCount(lock) < 1) ||
(token.IsAttached(this->Internals->GetWriteCount(lock))));
}
//// Returns true if write operations can currently be performed.
///
VTKM_CONT bool CanWrite(const LockType& lock, const vtkm::cont::Token& token) const
{
return (((*this->Internals->GetWriteCount(lock) < 1) ||
(token.IsAttached(this->Internals->GetWriteCount(lock)))) &&
((*this->Internals->GetReadCount(lock) < 1) ||
((*this->Internals->GetReadCount(lock) == 1) &&
token.IsAttached(this->Internals->GetReadCount(lock)))));
}
//// Will block the current thread until a read can be performed.
///
VTKM_CONT void WaitToRead(LockType& lock, const vtkm::cont::Token& token) const
{
// Note that if you deadlocked here, that means that you are trying to do a read operation on
// an array where an object is writing to it. This could happen on the same thread. For
// example, if you call `GetPortalControl()` then no other operation that can result in reading
// or writing data in the array can happen while the resulting portal is still in scope.
this->Internals->ConditionVariable.wait(
lock, [&lock, &token, this] { return this->CanRead(lock, token); });
}
//// Will block the current thread until a write can be performed.
///
VTKM_CONT void WaitToWrite(LockType& lock, const vtkm::cont::Token& token) const
{
// Note that if you deadlocked here, that means that you are trying to do a write operation on
// an array where an object is reading or writing to it. This could happen on the same thread.
// For example, if you call `GetPortalControl()` then no other operation that can result in
// reading or writing data in the array can happen while the resulting portal is still in
// scope.
this->Internals->ConditionVariable.wait(
lock, [&lock, &token, this] { return this->CanWrite(lock, token); });
}
/// Gets this array handle ready to interact with the given device. If the
/// array handle has already interacted with this device, then this method
/// does nothing. Although the internal state of this class can change, the
/// method is declared const because logically the data does not.
///
template <typename DeviceAdapterTag>
VTKM_CONT void PrepareForDevice(LockType& lock, DeviceAdapterTag) const;
/// Synchronizes the control array with the execution array. If either the
/// user array or control array is already valid, this method does nothing
/// (because the data is already available in the control environment).
/// Although the internal state of this class can change, the method is
/// declared const because logically the data does not.
///
VTKM_CONT void SyncControlArray(LockType& lock) const;
vtkm::Id GetNumberOfValues(LockType& lock) const;
VTKM_CONT
void ReleaseResourcesExecutionInternal()
void ReleaseResourcesExecutionInternal(LockType& lock) const
{
if (this->Internals->ExecutionArrayValid)
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->ExecutionArray->ReleaseResources();
this->Internals->ExecutionArrayValid = false;
this->WaitToWrite(lock, vtkm::cont::Token{});
// Note that it is possible that while waiting someone else deleted the execution array.
// That is why we check again.
}
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->GetExecutionArray(lock)->ReleaseResources();
this->Internals->SetExecutionArrayValid(lock, false);
}
}
/// Returns the DeviceAdapterId for the current device. If there is no device
/// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is
/// returned.
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const
{
return this->Internals->ExecutionArrayValid
? this->Internals->ExecutionArray->GetDeviceAdapterId()
: DeviceAdapterTagUndefined{};
}
struct VTKM_ALWAYS_EXPORT InternalStruct
class VTKM_ALWAYS_EXPORT InternalStruct
{
mutable StorageType ControlArray;
mutable bool ControlArrayValid;
mutable bool ControlArrayValid = false;
mutable std::unique_ptr<
vtkm::cont::internal::ArrayHandleExecutionManagerBase<ValueType, StorageTag>>
ExecutionArray;
mutable bool ExecutionArrayValid;
mutable std::unique_ptr<ExecutionManagerType> ExecutionArray;
mutable bool ExecutionArrayValid = false;
mutable vtkm::cont::Token::ReferenceCount ReadCount = 0;
mutable vtkm::cont::Token::ReferenceCount WriteCount = 0;
VTKM_CONT void CheckLock(const LockType& lock) const
{
VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock()));
}
public:
MutexType Mutex;
std::condition_variable ConditionVariable;
InternalStruct() = default;
InternalStruct(const StorageType& storage);
InternalStruct(StorageType&& storage);
#ifdef VTKM_ASSERTS_CHECKED
~InternalStruct()
{
// It should not be possible to destroy this array if any tokens are still attached to it.
LockType lock(this->Mutex);
VTKM_ASSERT((*this->GetReadCount(lock) == 0) && (*this->GetWriteCount(lock) == 0));
}
#else
~InternalStruct() = default;
#endif
// To access any feature in InternalStruct, you must have locked the mutex. You have
// to prove it by passing in a reference to a std::unique_lock.
VTKM_CONT bool IsControlArrayValid(const LockType& lock) const
{
this->CheckLock(lock);
return this->ControlArrayValid;
}
VTKM_CONT void SetControlArrayValid(const LockType& lock, bool value)
{
this->CheckLock(lock);
this->ControlArrayValid = value;
}
VTKM_CONT StorageType* GetControlArray(const LockType& lock) const
{
this->CheckLock(lock);
return &this->ControlArray;
}
VTKM_CONT bool IsExecutionArrayValid(const LockType& lock) const
{
this->CheckLock(lock);
return this->ExecutionArrayValid;
}
VTKM_CONT void SetExecutionArrayValid(const LockType& lock, bool value)
{
this->CheckLock(lock);
this->ExecutionArrayValid = value;
}
VTKM_CONT ExecutionManagerType* GetExecutionArray(const LockType& lock) const
{
this->CheckLock(lock);
return this->ExecutionArray.get();
}
VTKM_CONT void DeleteExecutionArray(const LockType& lock)
{
this->CheckLock(lock);
this->ExecutionArray.reset();
this->ExecutionArrayValid = false;
}
template <typename DeviceAdapterTag>
VTKM_CONT void NewExecutionArray(const LockType& lock, DeviceAdapterTag)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
this->CheckLock(lock);
VTKM_ASSERT(this->ExecutionArray == nullptr);
VTKM_ASSERT(!this->ExecutionArrayValid);
this->ExecutionArray.reset(
new vtkm::cont::internal::ArrayHandleExecutionManager<T, StorageTag, DeviceAdapterTag>(
&this->ControlArray));
}
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetReadCount(const LockType& lock) const
{
this->CheckLock(lock);
return &this->ReadCount;
}
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetWriteCount(const LockType& lock) const
{
this->CheckLock(lock);
return &this->WriteCount;
}
};
VTKM_CONT
@ -531,8 +804,7 @@ make_ArrayHandle(const T* array, vtkm::Id length, vtkm::CopyFlag copy = vtkm::Co
{
ArrayHandleType handle;
handle.Allocate(length);
std::copy(
array, array + length, vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalControl()));
std::copy(array, array + length, vtkm::cont::ArrayPortalToIteratorBegin(handle.WritePortal()));
return handle;
}
else
@ -634,7 +906,7 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle(
bool full = false)
{
using ArrayType = vtkm::cont::ArrayHandle<T, StorageT>;
using PortalType = typename ArrayType::PortalConstControl;
using PortalType = typename ArrayType::ReadPortalType;
using IsVec = typename vtkm::VecTraits<T>::HasMultipleComponents;
vtkm::Id sz = array.GetNumberOfValues();
@ -642,7 +914,7 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle(
out << "valueType=" << typeid(T).name() << " storageType=" << typeid(StorageT).name()
<< " numValues=" << sz << " bytes=" << (static_cast<size_t>(sz) * sizeof(T)) << " [";
PortalType portal = array.GetPortalConstControl();
PortalType portal = array.ReadPortal();
if (full || sz <= 7)
{
for (vtkm::Id i = 0; i < sz; i++)

@ -18,11 +18,26 @@ namespace cont
{
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle()
: Internals(new InternalStruct)
ArrayHandle<T, S>::InternalStruct::InternalStruct(
const typename ArrayHandle<T, S>::StorageType& storage)
: ControlArray(storage)
, ControlArrayValid(true)
, ExecutionArrayValid(false)
{
}
template <typename T, typename S>
ArrayHandle<T, S>::InternalStruct::InternalStruct(typename ArrayHandle<T, S>::StorageType&& storage)
: ControlArray(std::move(storage))
, ControlArrayValid(true)
, ExecutionArrayValid(false)
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle()
: Internals(std::make_shared<InternalStruct>())
{
this->Internals->ControlArrayValid = false;
this->Internals->ExecutionArrayValid = false;
}
template <typename T, typename S>
@ -39,20 +54,14 @@ ArrayHandle<T, S>::ArrayHandle(ArrayHandle<T, S>&& src) noexcept
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(const typename ArrayHandle<T, S>::StorageType& storage)
: Internals(new InternalStruct)
: Internals(std::make_shared<InternalStruct>(storage))
{
this->Internals->ControlArray = storage;
this->Internals->ControlArrayValid = true;
this->Internals->ExecutionArrayValid = false;
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(typename ArrayHandle<T, S>::StorageType&& storage) noexcept
: Internals(new InternalStruct)
: Internals(std::make_shared<InternalStruct>(std::move(storage)))
{
this->Internals->ControlArray = std::move(storage);
this->Internals->ControlArrayValid = true;
this->Internals->ExecutionArrayValid = false;
}
template <typename T, typename S>
@ -77,10 +86,12 @@ ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(ArrayHandle<T, S>&& src) noexcep
template <typename T, typename S>
typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage()
{
this->SyncControlArray();
if (this->Internals->ControlArrayValid)
LockType lock = this->GetLock();
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->ControlArray;
return *this->Internals->GetControlArray(lock);
}
else
{
@ -92,10 +103,12 @@ typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage()
template <typename T, typename S>
const typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage() const
{
this->SyncControlArray();
if (this->Internals->ControlArrayValid)
LockType lock = this->GetLock();
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->ControlArray;
return *this->Internals->GetControlArray(lock);
}
else
{
@ -105,16 +118,18 @@ const typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage() c
}
template <typename T, typename S>
typename ArrayHandle<T, S>::PortalControl ArrayHandle<T, S>::GetPortalControl()
typename ArrayHandle<T, S>::StorageType::PortalType ArrayHandle<T, S>::GetPortalControl()
{
this->SyncControlArray();
if (this->Internals->ControlArrayValid)
LockType lock = this->GetLock();
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
// If the user writes into the iterator we return, then the execution
// array will become invalid. Play it safe and release the execution
// resources. (Use the const version to preserve the execution array.)
this->ReleaseResourcesExecutionInternal();
return this->Internals->ControlArray.GetPortal();
this->ReleaseResourcesExecutionInternal(lock);
return this->Internals->GetControlArray(lock)->GetPortal();
}
else
{
@ -124,12 +139,15 @@ typename ArrayHandle<T, S>::PortalControl ArrayHandle<T, S>::GetPortalControl()
}
template <typename T, typename S>
typename ArrayHandle<T, S>::PortalConstControl ArrayHandle<T, S>::GetPortalConstControl() const
typename ArrayHandle<T, S>::StorageType::PortalConstType ArrayHandle<T, S>::GetPortalConstControl()
const
{
this->SyncControlArray();
if (this->Internals->ControlArrayValid)
LockType lock = this->GetLock();
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->ControlArray.GetPortalConst();
return this->Internals->GetControlArray(lock)->GetPortalConst();
}
else
{
@ -139,15 +157,62 @@ typename ArrayHandle<T, S>::PortalConstControl ArrayHandle<T, S>::GetPortalConst
}
template <typename T, typename S>
vtkm::Id ArrayHandle<T, S>::GetNumberOfValues() const
typename ArrayHandle<T, S>::ReadPortalType ArrayHandle<T, S>::ReadPortal() const
{
if (this->Internals->ControlArrayValid)
LockType lock = this->GetLock();
vtkm::cont::Token token;
this->WaitToRead(lock, token);
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->ControlArray.GetNumberOfValues();
token.Attach(
*this, this->Internals->GetReadCount(lock), lock, &this->Internals->ConditionVariable);
return ReadPortalType(std::move(token),
this->Internals->GetControlArray(lock)->GetPortalConst());
}
else if (this->Internals->ExecutionArrayValid)
else
{
return this->Internals->ExecutionArray->GetNumberOfValues();
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
template <typename T, typename S>
typename ArrayHandle<T, S>::WritePortalType ArrayHandle<T, S>::WritePortal() const
{
LockType lock = this->GetLock();
vtkm::cont::Token token;
this->WaitToWrite(lock, token);
this->SyncControlArray(lock);
if (this->Internals->IsControlArrayValid(lock))
{
// If the user writes into the iterator we return, then the execution
// array will become invalid. Play it safe and release the execution
// resources. (Use the const version to preserve the execution array.)
this->ReleaseResourcesExecutionInternal(lock);
token.Attach(
*this, this->Internals->GetWriteCount(lock), lock, &this->Internals->ConditionVariable);
return WritePortalType(std::move(token), this->Internals->GetControlArray(lock)->GetPortal());
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
template <typename T, typename S>
vtkm::Id ArrayHandle<T, S>::GetNumberOfValues(LockType& lock) const
{
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->GetControlArray(lock)->GetNumberOfValues();
}
else if (this->Internals->IsExecutionArrayValid(lock))
{
return this->Internals->GetExecutionArray(lock)->GetNumberOfValues();
}
else
{
@ -162,17 +227,20 @@ void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues)
if (numberOfValues > 0)
{
vtkm::Id originalNumberOfValues = this->GetNumberOfValues();
LockType lock = this->GetLock();
vtkm::Id originalNumberOfValues = this->GetNumberOfValues(lock);
if (numberOfValues < originalNumberOfValues)
{
if (this->Internals->ControlArrayValid)
this->WaitToWrite(lock, vtkm::cont::Token{});
if (this->Internals->IsControlArrayValid(lock))
{
this->Internals->ControlArray.Shrink(numberOfValues);
this->Internals->GetControlArray(lock)->Shrink(numberOfValues);
}
if (this->Internals->ExecutionArrayValid)
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->ExecutionArray->Shrink(numberOfValues);
this->Internals->GetExecutionArray(lock)->Shrink(numberOfValues);
}
}
else if (numberOfValues == originalNumberOfValues)
@ -184,7 +252,7 @@ void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues)
throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array.");
}
VTKM_ASSERT(this->GetNumberOfValues() == numberOfValues);
VTKM_ASSERT(this->GetNumberOfValues(lock) == numberOfValues);
}
else // numberOfValues == 0
{
@ -198,24 +266,29 @@ void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues)
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::PortalConst
ArrayHandle<T, S>::PrepareForInput(DeviceAdapterTag) const
ArrayHandle<T, S>::PrepareForInput(DeviceAdapterTag device, vtkm::cont::Token& token) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
if (!this->Internals->ControlArrayValid && !this->Internals->ExecutionArrayValid)
LockType lock = this->GetLock();
this->WaitToRead(lock, token);
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
{
// Want to use an empty array.
// Set up ArrayHandle state so this actually works.
this->Internals->ControlArray.Allocate(0);
this->Internals->ControlArrayValid = true;
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
this->PrepareForDevice(DeviceAdapterTag());
typename ExecutionTypes<DeviceAdapterTag>::PortalConst portal =
this->Internals->ExecutionArray->PrepareForInput(!this->Internals->ExecutionArrayValid,
DeviceAdapterTag());
this->PrepareForDevice(lock, device);
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInput(
!this->Internals->IsExecutionArrayValid(lock), device, token);
this->Internals->ExecutionArrayValid = true;
this->Internals->SetExecutionArrayValid(lock, true);
token.Attach(
*this, this->Internals->GetReadCount(lock), lock, &this->Internals->ConditionVariable);
return portal;
}
@ -223,18 +296,23 @@ typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::PortalCon
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues,
DeviceAdapterTag device,
vtkm::cont::Token& token)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
// Invalidate any control arrays.
// Should the control array resource be released? Probably not a good
// idea when shared with execution.
this->Internals->ControlArrayValid = false;
this->Internals->SetControlArrayValid(lock, false);
this->PrepareForDevice(DeviceAdapterTag());
typename ExecutionTypes<DeviceAdapterTag>::Portal portal =
this->Internals->ExecutionArray->PrepareForOutput(numberOfValues, DeviceAdapterTag());
this->PrepareForDevice(lock, device);
auto portal =
this->Internals->GetExecutionArray(lock)->PrepareForOutput(numberOfValues, device, token);
// We are assuming that the calling code will fill the array using the
// iterators we are returning, so go ahead and mark the execution array as
@ -245,7 +323,10 @@ ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
// implementation the only access to the array is through the iterators
// returned from this method, so you would have to work to invalidate this
// assumption anyway.)
this->Internals->ExecutionArrayValid = true;
this->Internals->SetExecutionArrayValid(lock, true);
token.Attach(
*this, this->Internals->GetWriteCount(lock), lock, &this->Internals->ConditionVariable);
return portal;
}
@ -253,40 +334,45 @@ ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, S>::PrepareForInPlace(DeviceAdapterTag)
ArrayHandle<T, S>::PrepareForInPlace(DeviceAdapterTag device, vtkm::cont::Token& token)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
if (!this->Internals->ControlArrayValid && !this->Internals->ExecutionArrayValid)
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
{
// Want to use an empty array.
// Set up ArrayHandle state so this actually works.
this->Internals->ControlArray.Allocate(0);
this->Internals->ControlArrayValid = true;
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
this->PrepareForDevice(DeviceAdapterTag());
typename ExecutionTypes<DeviceAdapterTag>::Portal portal =
this->Internals->ExecutionArray->PrepareForInPlace(!this->Internals->ExecutionArrayValid,
DeviceAdapterTag());
this->PrepareForDevice(lock, device);
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInPlace(
!this->Internals->IsExecutionArrayValid(lock), device, token);
this->Internals->ExecutionArrayValid = true;
this->Internals->SetExecutionArrayValid(lock, true);
// Invalidate any control arrays since their data will become invalid when
// the execution data is overwritten. Don't actually release the control
// array. It may be shared as the execution array.
this->Internals->ControlArrayValid = false;
this->Internals->SetControlArrayValid(lock, false);
token.Attach(
*this, this->Internals->GetWriteCount(lock), lock, &this->Internals->ConditionVariable);
return portal;
}
template <typename T, typename S>
template <typename DeviceAdapterTag>
void ArrayHandle<T, S>::PrepareForDevice(DeviceAdapterTag) const
void ArrayHandle<T, S>::PrepareForDevice(LockType& lock, DeviceAdapterTag device) const
{
if (this->Internals->ExecutionArray != nullptr)
if (this->Internals->GetExecutionArray(lock) != nullptr)
{
if (this->Internals->ExecutionArray->IsDeviceAdapter(DeviceAdapterTag()))
if (this->Internals->GetExecutionArray(lock)->IsDeviceAdapter(DeviceAdapterTag()))
{
// Already have manager for correct device adapter. Nothing to do.
return;
@ -294,47 +380,53 @@ void ArrayHandle<T, S>::PrepareForDevice(DeviceAdapterTag) const
else
{
// Have the wrong manager. Delete the old one and create a new one
// of the right type. (BTW, it would be possible for the array handle
// to hold references to execution arrays on multiple devices. However,
// there is not a clear use case for that yet and it is unclear what
// the behavior of "dirty" arrays should be, so it is not currently
// implemented.)
this->SyncControlArray();
// of the right type. (TODO: it would be possible for the array handle
// to hold references to execution arrays on multiple devices. When data
// are written on one devices, all the other devices should get cleared.)
// BUG: There is a non-zero chance that while waiting for the write lock, another thread
// could change the ExecutionInterface, which would cause problems. In the future we should
// support multiple devices, in which case we would not have to delete one execution array
// to load another.
this->WaitToWrite(lock, vtkm::cont::Token{}); // Make sure no one is reading device array
this->SyncControlArray(lock);
// Need to change some state that does not change the logical state from
// an external point of view.
this->Internals->ExecutionArray.reset();
this->Internals->ExecutionArrayValid = false;
this->Internals->DeleteExecutionArray(lock);
}
}
VTKM_ASSERT(this->Internals->ExecutionArray == nullptr);
VTKM_ASSERT(!this->Internals->ExecutionArrayValid);
// Need to change some state that does not change the logical state from
// an external point of view.
this->Internals->ExecutionArray.reset(
new vtkm::cont::internal::ArrayHandleExecutionManager<T, StorageTag, DeviceAdapterTag>(
&this->Internals->ControlArray));
this->Internals->NewExecutionArray(lock, device);
}
template <typename T, typename S>
void ArrayHandle<T, S>::SyncControlArray() const
void ArrayHandle<T, S>::SyncControlArray(LockType& lock) const
{
if (!this->Internals->ControlArrayValid)
if (!this->Internals->IsControlArrayValid(lock))
{
// It may be the case that `SyncControlArray` is called from a method that has a `Token`.
// However, if we are here, that `Token` should not already be attached to this array.
// If it were, then there should be no reason to move data arround (unless the `Token`
// was used when preparing for multiple devices, which it should not be used like that).
this->WaitToRead(lock, vtkm::cont::Token{});
// Need to change some state that does not change the logical state from
// an external point of view.
if (this->Internals->ExecutionArrayValid)
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->ExecutionArray->RetrieveOutputData(&this->Internals->ControlArray);
this->Internals->ControlArrayValid = true;
this->Internals->GetExecutionArray(lock)->RetrieveOutputData(
this->Internals->GetControlArray(lock));
this->Internals->SetControlArrayValid(lock, true);
}
else
{
// This array is in the null state (there is nothing allocated), but
// the calling function wants to do something with the array. Put this
// class into a valid state by allocating an array of size 0.
this->Internals->ControlArray.Allocate(0);
this->Internals->ControlArrayValid = true;
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
}
}
@ -359,7 +451,7 @@ inline void VTKM_CONT StorageSerialization(vtkmdiy::BinaryBuffer& bb,
vtkmdiy::save(bb, count);
vtkmdiy::save(bb, vtkm::Id(0)); //not a basic storage
auto portal = obj.GetPortalConstControl();
auto portal = obj.ReadPortal();
for (vtkm::Id i = 0; i < count; ++i)
{
vtkmdiy::save(bb, portal.Get(i));
@ -409,7 +501,7 @@ VTKM_CONT void Serialization<vtkm::cont::ArrayHandle<T>>::load(BinaryBuffer& bb,
}
else
{
auto portal = obj.GetPortalControl();
auto portal = obj.WritePortal();
for (vtkm::Id i = 0; i < count; ++i)
{
T val{};

@ -88,10 +88,10 @@ public:
VTKM_CONT Storage& operator=(Storage&&) noexcept = default;
VTKM_CONT
PortalType GetPortal() { return PortalType{ this->Data.GetPortalControl() }; }
PortalType GetPortal() { return PortalType{ this->Data.WritePortal() }; }
VTKM_CONT
PortalConstType GetPortalConst() { return PortalConstType{ this->Data.GetPortalConstControl() }; }
PortalConstType GetPortalConst() { return PortalConstType{ this->Data.ReadPortal() }; }
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Data.GetNumberOfBits(); }
VTKM_CONT void Allocate(vtkm::Id numberOfValues) { this->Data.Allocate(numberOfValues); }
@ -129,21 +129,21 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Data.GetNumberOfBits(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution{ this->Data.PrepareForInput(Device{}) };
return PortalConstExecution{ this->Data.PrepareForInput(Device{}, token) };
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution{ this->Data.PrepareForInPlace(Device{}) };
return PortalExecution{ this->Data.PrepareForInPlace(Device{}, token) };
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution{ this->Data.PrepareForOutput(numberOfValues, Device{}) };
return PortalExecution{ this->Data.PrepareForOutput(numberOfValues, Device{}, token) };
}
VTKM_CONT

@ -14,6 +14,7 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/Token.h>
namespace vtkm
{
@ -154,54 +155,69 @@ namespace vtkm
namespace cont
{
namespace internal
{
template <typename FirstHandleType, typename SecondHandleType, typename ThirdHandleType>
template <typename StorageTag1, typename StorageTag2, typename StorageTag3>
struct VTKM_ALWAYS_EXPORT StorageTagCartesianProduct
{
};
namespace internal
{
/// This helper struct defines the value type for a zip container containing
/// the given two array handles.
///
template <typename FirstHandleType, typename SecondHandleType, typename ThirdHandleType>
template <typename AH1, typename AH2, typename AH3>
struct ArrayHandleCartesianProductTraits
{
VTKM_IS_ARRAY_HANDLE(AH1);
VTKM_IS_ARRAY_HANDLE(AH2);
VTKM_IS_ARRAY_HANDLE(AH3);
using ComponentType = typename AH1::ValueType;
VTKM_STATIC_ASSERT_MSG(
(std::is_same<ComponentType, typename AH2::ValueType>::value),
"All arrays for ArrayHandleCartesianProduct must have the same value type. "
"Use ArrayHandleCast as necessary to make types match.");
VTKM_STATIC_ASSERT_MSG(
(std::is_same<ComponentType, typename AH3::ValueType>::value),
"All arrays for ArrayHandleCartesianProduct must have the same value type. "
"Use ArrayHandleCast as necessary to make types match.");
/// The ValueType (a pair containing the value types of the two arrays).
///
using ValueType = vtkm::Vec<typename FirstHandleType::ValueType, 3>;
using ValueType = vtkm::Vec<ComponentType, 3>;
/// The appropriately templated tag.
///
using Tag = StorageTagCartesianProduct<FirstHandleType, SecondHandleType, ThirdHandleType>;
using Tag = vtkm::cont::StorageTagCartesianProduct<typename AH1::StorageTag,
typename AH2::StorageTag,
typename AH3::StorageTag>;
/// The superclass for ArrayHandleCartesianProduct.
///
using Superclass = vtkm::cont::ArrayHandle<ValueType, Tag>;
};
template <typename FirstHandleType, typename SecondHandleType, typename ThirdHandleType>
class Storage<vtkm::Vec<typename FirstHandleType::ValueType, 3>,
StorageTagCartesianProduct<FirstHandleType, SecondHandleType, ThirdHandleType>>
template <typename T, typename ST1, typename ST2, typename ST3>
class Storage<vtkm::Vec<T, 3>, vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>
{
VTKM_IS_ARRAY_HANDLE(FirstHandleType);
VTKM_IS_ARRAY_HANDLE(SecondHandleType);
VTKM_IS_ARRAY_HANDLE(ThirdHandleType);
using AH1 = vtkm::cont::ArrayHandle<T, ST1>;
using AH2 = vtkm::cont::ArrayHandle<T, ST2>;
using AH3 = vtkm::cont::ArrayHandle<T, ST3>;
public:
using ValueType = vtkm::Vec<typename FirstHandleType::ValueType, 3>;
using ValueType = vtkm::Vec<typename AH1::ValueType, 3>;
using PortalType =
vtkm::exec::internal::ArrayPortalCartesianProduct<ValueType,
typename FirstHandleType::PortalControl,
typename SecondHandleType::PortalControl,
typename ThirdHandleType::PortalControl>;
typename AH1::WritePortalType,
typename AH2::WritePortalType,
typename AH3::WritePortalType>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalCartesianProduct<ValueType,
typename FirstHandleType::PortalConstControl,
typename SecondHandleType::PortalConstControl,
typename ThirdHandleType::PortalConstControl>;
typename AH1::ReadPortalType,
typename AH2::ReadPortalType,
typename AH3::ReadPortalType>;
VTKM_CONT
Storage()
@ -212,9 +228,7 @@ public:
}
VTKM_CONT
Storage(const FirstHandleType& array1,
const SecondHandleType& array2,
const ThirdHandleType& array3)
Storage(const AH1& array1, const AH2& array2, const AH3& array3)
: FirstArray(array1)
, SecondArray(array2)
, ThirdArray(array3)
@ -224,17 +238,16 @@ public:
VTKM_CONT
PortalType GetPortal()
{
return PortalType(this->FirstArray.GetPortalControl(),
this->SecondArray.GetPortalControl(),
this->ThirdArray.GetPortalControl());
return PortalType(this->FirstArray.WritePortal(),
this->SecondArray.WritePortal(),
this->ThirdArray.WritePortal());
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
return PortalConstType(this->FirstArray.GetPortalConstControl(),
this->SecondArray.GetPortalConstControl(),
this->ThirdArray.GetPortalConstControl());
return PortalConstType(
this->FirstArray.ReadPortal(), this->SecondArray.ReadPortal(), this->ThirdArray.ReadPortal());
}
VTKM_CONT
@ -264,33 +277,32 @@ public:
}
VTKM_CONT
const FirstHandleType& GetFirstArray() const { return this->FirstArray; }
const AH1& GetFirstArray() const { return this->FirstArray; }
VTKM_CONT
const SecondHandleType& GetSecondArray() const { return this->SecondArray; }
const AH2& GetSecondArray() const { return this->SecondArray; }
VTKM_CONT
const ThirdHandleType& GetThirdArray() const { return this->ThirdArray; }
const AH3& GetThirdArray() const { return this->ThirdArray; }
private:
FirstHandleType FirstArray;
SecondHandleType SecondArray;
ThirdHandleType ThirdArray;
AH1 FirstArray;
AH2 SecondArray;
AH3 ThirdArray;
};
template <typename FirstHandleType,
typename SecondHandleType,
typename ThirdHandleType,
typename Device>
class ArrayTransfer<vtkm::Vec<typename FirstHandleType::ValueType, 3>,
StorageTagCartesianProduct<FirstHandleType, SecondHandleType, ThirdHandleType>,
Device>
template <typename T, typename ST1, typename ST2, typename ST3, typename Device>
class ArrayTransfer<vtkm::Vec<T, 3>, vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>, Device>
{
public:
using ValueType = vtkm::Vec<typename FirstHandleType::ValueType, 3>;
using ValueType = vtkm::Vec<T, 3>;
private:
using StorageTag = StorageTagCartesianProduct<FirstHandleType, SecondHandleType, ThirdHandleType>;
using AH1 = vtkm::cont::ArrayHandle<T, ST1>;
using AH2 = vtkm::cont::ArrayHandle<T, ST2>;
using AH3 = vtkm::cont::ArrayHandle<T, ST3>;
using StorageTag = vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
@ -299,15 +311,15 @@ public:
using PortalExecution = vtkm::exec::internal::ArrayPortalCartesianProduct<
ValueType,
typename FirstHandleType::template ExecutionTypes<Device>::Portal,
typename SecondHandleType::template ExecutionTypes<Device>::Portal,
typename ThirdHandleType::template ExecutionTypes<Device>::Portal>;
typename AH1::template ExecutionTypes<Device>::Portal,
typename AH2::template ExecutionTypes<Device>::Portal,
typename AH3::template ExecutionTypes<Device>::Portal>;
using PortalConstExecution = vtkm::exec::internal::ArrayPortalCartesianProduct<
ValueType,
typename FirstHandleType::template ExecutionTypes<Device>::PortalConst,
typename SecondHandleType::template ExecutionTypes<Device>::PortalConst,
typename ThirdHandleType::template ExecutionTypes<Device>::PortalConst>;
typename AH1::template ExecutionTypes<Device>::PortalConst,
typename AH2::template ExecutionTypes<Device>::PortalConst,
typename AH3::template ExecutionTypes<Device>::PortalConst>;
VTKM_CONT
ArrayTransfer(StorageType* storage)
@ -325,15 +337,15 @@ public:
}
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->FirstArray.PrepareForInput(Device()),
this->SecondArray.PrepareForInput(Device()),
this->ThirdArray.PrepareForInput(Device()));
return PortalConstExecution(this->FirstArray.PrepareForInput(Device(), token),
this->SecondArray.PrepareForInput(Device(), token),
this->ThirdArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadAllocation(
"Cannot write to an ArrayHandleCartesianProduct. It does not make "
@ -341,7 +353,7 @@ public:
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues))
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadAllocation(
"Cannot write to an ArrayHandleCartesianProduct. It does not make "
@ -371,9 +383,9 @@ public:
}
private:
FirstHandleType FirstArray;
SecondHandleType SecondArray;
ThirdHandleType ThirdArray;
AH1 FirstArray;
AH2 SecondArray;
AH3 ThirdArray;
};
} // namespace internal
@ -412,6 +424,13 @@ public:
: Superclass(StorageType(firstArray, secondArray, thirdArray))
{
}
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
~ArrayHandleCartesianProduct() {}
};
/// A convenience function for creating an ArrayHandleCartesianProduct. It takes the two
@ -449,11 +468,12 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleCartesianProduct<AH1, AH2,
}
};
template <typename AH1, typename AH2, typename AH3>
template <typename T, typename ST1, typename ST2, typename ST3>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::Vec<typename AH1::ValueType, 3>,
vtkm::cont::internal::StorageTagCartesianProduct<AH1, AH2, AH3>>>
: SerializableTypeString<vtkm::cont::ArrayHandleCartesianProduct<AH1, AH2, AH3>>
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>>
: SerializableTypeString<vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>>
{
};
}
@ -492,11 +512,12 @@ public:
}
};
template <typename AH1, typename AH2, typename AH3>
template <typename T, typename ST1, typename ST2, typename ST3>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::Vec<typename AH1::ValueType, 3>,
vtkm::cont::internal::StorageTagCartesianProduct<AH1, AH2, AH3>>>
: Serialization<vtkm::cont::ArrayHandleCartesianProduct<AH1, AH2, AH3>>
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>>
: Serialization<vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>>
{
};
} // diy

@ -24,14 +24,127 @@ namespace vtkm
namespace cont
{
template <typename SourceT, typename SourceStorage>
struct VTKM_ALWAYS_EXPORT StorageTagCast
{
};
namespace internal
{
template <typename FromType, typename ToType>
struct VTKM_ALWAYS_EXPORT Cast
{
// The following operator looks like it should never issue a cast warning because of
// the static_cast (and we don't want it to issue a warning). However, if ToType is
// an object that has a constructor that takes a value that FromType can be cast to,
// that cast can cause a warning. For example, if FromType is vtkm::Float64 and ToType
// is vtkm::Vec<vtkm::Float32, 3>, the static_cast will first implicitly cast the
// Float64 to a Float32 (which causes a warning) before using the static_cast to
// construct the Vec with the Float64. The easiest way around the problem is to
// just disable all conversion warnings here. (The pragmas are taken from those
// used in Types.h for the VecBase class.)
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif // gcc || clang
#endif //not using cuda < 8
#if defined(VTKM_MSVC)
#pragma warning(push)
#pragma warning(disable : 4244)
#endif
VTKM_EXEC_CONT
ToType operator()(const FromType& val) const { return static_cast<ToType>(val); }
#if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
#pragma GCC diagnostic pop
#endif // gcc || clang
#endif // not using cuda < 8
#if defined(VTKM_MSVC)
#pragma warning(pop)
#endif
};
namespace detail
{
template <typename TargetT, typename SourceT, typename SourceStorage, bool... CastFlags>
struct ArrayHandleCastTraits;
template <typename TargetT, typename SourceT, typename SourceStorage>
struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage>
: ArrayHandleCastTraits<TargetT,
SourceT,
SourceStorage,
std::is_convertible<SourceT, TargetT>::value,
std::is_convertible<TargetT, SourceT>::value>
{
};
// Case where the forward cast is invalid, so this array is invalid.
template <typename TargetT, typename SourceT, typename SourceStorage, bool CanCastBackward>
struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, false, CanCastBackward>
{
struct StorageSuperclass : vtkm::cont::internal::UndefinedStorage
{
using PortalType = vtkm::cont::internal::detail::UndefinedArrayPortal<TargetT>;
using PortalConstType = vtkm::cont::internal::detail::UndefinedArrayPortal<TargetT>;
};
};
// Case where the forward cast is valid but the backward cast is invalid.
template <typename TargetT, typename SourceT, typename SourceStorage>
struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, true, false>
{
using StorageTagSuperclass = StorageTagTransform<vtkm::cont::ArrayHandle<SourceT, SourceStorage>,
vtkm::cont::internal::Cast<SourceT, TargetT>>;
using StorageSuperclass = vtkm::cont::internal::Storage<TargetT, StorageTagSuperclass>;
template <typename Device>
using ArrayTransferSuperclass = ArrayTransfer<TargetT, StorageTagSuperclass, Device>;
};
// Case where both forward and backward casts are valid.
template <typename TargetT, typename SourceT, typename SourceStorage>
struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, true, true>
{
using StorageTagSuperclass = StorageTagTransform<vtkm::cont::ArrayHandle<SourceT, SourceStorage>,
vtkm::cont::internal::Cast<SourceT, TargetT>,
vtkm::cont::internal::Cast<TargetT, SourceT>>;
using StorageSuperclass = vtkm::cont::internal::Storage<TargetT, StorageTagSuperclass>;
template <typename Device>
using ArrayTransferSuperclass = ArrayTransfer<TargetT, StorageTagSuperclass, Device>;
};
} // namespace detail
template <typename TargetT, typename SourceT, typename SourceStorage>
struct Storage<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>
: detail::ArrayHandleCastTraits<TargetT, SourceT, SourceStorage>::StorageSuperclass
{
using Superclass =
typename detail::ArrayHandleCastTraits<TargetT, SourceT, SourceStorage>::StorageSuperclass;
using Superclass::Superclass;
};
template <typename TargetT, typename SourceT, typename SourceStorage, typename Device>
struct ArrayTransfer<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>, Device>
: detail::ArrayHandleCastTraits<TargetT,
SourceT,
SourceStorage>::template ArrayTransferSuperclass<Device>
{
using Superclass =
typename detail::ArrayHandleCastTraits<TargetT,
SourceT,
SourceStorage>::template ArrayTransferSuperclass<Device>;
using Superclass::Superclass;
};
} // namespace internal
@ -44,24 +157,32 @@ struct VTKM_ALWAYS_EXPORT Cast
///
template <typename T, typename ArrayHandleType>
class ArrayHandleCast
: public vtkm::cont::ArrayHandleTransform<ArrayHandleType,
internal::Cast<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>
: public vtkm::cont::ArrayHandle<
T,
StorageTagCast<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag>>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleCast,
(ArrayHandleCast<T, ArrayHandleType>),
(vtkm::cont::ArrayHandleTransform<ArrayHandleType,
internal::Cast<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>));
(vtkm::cont::ArrayHandle<
T,
StorageTagCast<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag>>));
ArrayHandleCast(const ArrayHandleType& handle)
: Superclass(handle)
ArrayHandleCast(const vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
typename ArrayHandleType::StorageTag>& handle)
: Superclass(typename Superclass::StorageType(handle))
{
this->ValidateTypeCast<typename ArrayHandleType::ValueType>();
}
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
~ArrayHandleCast() {}
private:
// Log warnings if type cast is valid but lossy:
template <typename SrcValueType>
@ -161,23 +282,21 @@ namespace vtkm
namespace cont
{
template <typename T1, typename T2>
struct SerializableTypeString<vtkm::cont::internal::Cast<T1, T2>>
template <typename T, typename AH>
struct SerializableTypeString<vtkm::cont::ArrayHandleCast<T, AH>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "AH_Cast_Functor<" + SerializableTypeString<T1>::Get() + "," +
SerializableTypeString<T2>::Get() + ">";
static std::string name = "AH_Cast<" + SerializableTypeString<T>::Get() + "," +
SerializableTypeString<typename AH::ValueType>::Get() + "," +
SerializableTypeString<typename AH::StorageTag>::Get() + ">";
return name;
}
};
template <typename T, typename AH>
struct SerializableTypeString<vtkm::cont::ArrayHandleCast<T, AH>>
: SerializableTypeString<
vtkm::cont::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
template <typename T1, typename T2, typename S>
struct SerializableTypeString<vtkm::cont::ArrayHandle<T1, vtkm::cont::StorageTagCast<T2, S>>>
: SerializableTypeString<vtkm::cont::ArrayHandleCast<T1, vtkm::cont::ArrayHandle<T2, S>>>
{
};
}
@ -186,20 +305,33 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleCast<T, AH>>
namespace mangled_diy_namespace
{
template <typename T1, typename T2>
struct Serialization<vtkm::cont::internal::Cast<T1, T2>>
template <typename TargetT, typename SourceT, typename SourceStorage>
struct Serialization<
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>>
{
static VTKM_CONT void save(BinaryBuffer&, const vtkm::cont::internal::Cast<T1, T2>&) {}
private:
using BaseType =
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>;
static VTKM_CONT void load(BinaryBuffer&, vtkm::cont::internal::Cast<T1, T2>&) {}
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
vtkmdiy::save(bb, obj.GetStorage().GetArray());
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
{
vtkm::cont::ArrayHandle<SourceT, SourceStorage> array;
vtkmdiy::load(bb, array);
obj = BaseType(array);
}
};
template <typename T, typename AH>
struct Serialization<vtkm::cont::ArrayHandleCast<T, AH>>
: Serialization<
vtkm::cont::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
template <typename TargetT, typename AH>
struct Serialization<vtkm::cont::ArrayHandleCast<TargetT, AH>>
: Serialization<vtkm::cont::ArrayHandle<
TargetT,
vtkm::cont::StorageTagCast<typename AH::ValueType, typename AH::StorageTag>>>
{
};

@ -12,6 +12,7 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/Deprecated.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/VecTraits.h>
@ -59,20 +60,6 @@ struct AllAreArrayHandles
constexpr static bool Value = AllAreArrayHandlesImpl<ArrayHandleTs...>::Value;
};
// ParamsAreArrayHandles: ------------------------------------------------------
// Same as AllAreArrayHandles, but accepts a tuple.
template <typename T>
struct ParamsAreArrayHandles
{
constexpr static bool Value = false;
};
template <typename... ArrayHandleTs>
struct ParamsAreArrayHandles<vtkmstd::tuple<ArrayHandleTs...>>
{
constexpr static bool Value = AllAreArrayHandlesImpl<ArrayHandleTs...>::Value;
};
// GetValueType: ---------------------------------------------------------------
// Determines the output ValueType of the objects in TupleType, a vtkmstd::tuple
// which can contain ArrayHandles, ArrayPortals...anything with a ValueType
@ -133,39 +120,45 @@ struct ArrayTupleForEach
template <typename PortalTuple>
VTKM_CONT static void GetPortalTupleControl(ArrayTuple& arrays, PortalTuple& portals)
{
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).GetPortalControl();
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).WritePortal();
Next::GetPortalTupleControl(arrays, portals);
}
template <typename PortalTuple>
VTKM_CONT static void GetPortalConstTupleControl(const ArrayTuple& arrays, PortalTuple& portals)
{
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).GetPortalConstControl();
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).ReadPortal();
Next::GetPortalConstTupleControl(arrays, portals);
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForInput(const ArrayTuple& arrays, PortalTuple& portals)
VTKM_CONT static void PrepareForInput(const ArrayTuple& arrays,
PortalTuple& portals,
vtkm::cont::Token& token)
{
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).PrepareForInput(DeviceTag());
Next::template PrepareForInput<DeviceTag>(arrays, portals);
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).PrepareForInput(DeviceTag(), token);
Next::template PrepareForInput<DeviceTag>(arrays, portals, token);
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForInPlace(ArrayTuple& arrays, PortalTuple& portals)
VTKM_CONT static void PrepareForInPlace(ArrayTuple& arrays,
PortalTuple& portals,
vtkm::cont::Token& token)
{
vtkmstd::get<Index>(portals) = vtkmstd::get<Index>(arrays).PrepareForInPlace(DeviceTag());
Next::template PrepareForInPlace<DeviceTag>(arrays, portals);
vtkmstd::get<Index>(portals) =
vtkmstd::get<Index>(arrays).PrepareForInPlace(DeviceTag(), token);
Next::template PrepareForInPlace<DeviceTag>(arrays, portals, token);
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForOutput(ArrayTuple& arrays,
PortalTuple& portals,
vtkm::Id numValues)
vtkm::Id numValues,
vtkm::cont::Token& token)
{
vtkmstd::get<Index>(portals) =
vtkmstd::get<Index>(arrays).PrepareForOutput(numValues, DeviceTag());
Next::template PrepareForOutput<DeviceTag>(arrays, portals, numValues);
vtkmstd::get<Index>(arrays).PrepareForOutput(numValues, DeviceTag(), token);
Next::template PrepareForOutput<DeviceTag>(arrays, portals, numValues, token);
}
VTKM_CONT
@ -204,17 +197,17 @@ struct ArrayTupleForEach<Index, Index, ArrayTuple>
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForInput(const ArrayTuple&, PortalTuple&)
VTKM_CONT static void PrepareForInput(const ArrayTuple&, PortalTuple&, vtkm::cont::Token&)
{
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForInPlace(ArrayTuple&, PortalTuple&)
VTKM_CONT static void PrepareForInPlace(ArrayTuple&, PortalTuple&, vtkm::cont::Token&)
{
}
template <typename DeviceTag, typename PortalTuple>
VTKM_CONT static void PrepareForOutput(ArrayTuple&, PortalTuple&, vtkm::Id)
VTKM_CONT static void PrepareForOutput(ArrayTuple&, PortalTuple&, vtkm::Id, vtkm::cont::Token&)
{
}
@ -235,10 +228,10 @@ template <typename Head, typename... Tail>
struct PortalTupleTypeGeneratorImpl<vtkmstd::tuple<Head, Tail...>>
{
using Next = PortalTupleTypeGeneratorImpl<vtkmstd::tuple<Tail...>>;
using PortalControlTuple = typename TupleTypePrepend<typename Head::PortalControl,
using PortalControlTuple = typename TupleTypePrepend<typename Head::WritePortalType,
typename Next::PortalControlTuple>::Type;
using PortalConstControlTuple =
typename TupleTypePrepend<typename Head::PortalConstControl,
typename TupleTypePrepend<typename Head::ReadPortalType,
typename Next::PortalConstControlTuple>::Type;
template <typename DeviceTag>
@ -256,8 +249,8 @@ struct PortalTupleTypeGeneratorImpl<vtkmstd::tuple<Head, Tail...>>
template <typename Head>
struct PortalTupleTypeGeneratorImpl<vtkmstd::tuple<Head>>
{
using PortalControlTuple = vtkmstd::tuple<typename Head::PortalControl>;
using PortalConstControlTuple = vtkmstd::tuple<typename Head::PortalConstControl>;
using PortalControlTuple = vtkmstd::tuple<typename Head::WritePortalType>;
using PortalConstControlTuple = vtkmstd::tuple<typename Head::ReadPortalType>;
template <typename DeviceTag>
struct ExecutionTypes
@ -315,29 +308,30 @@ public:
template <typename DeviceTag>
VTKM_CONT static const typename ExecutionTypes<DeviceTag>::PortalConstTuple PrepareForInput(
const ArrayTuple& arrays)
const ArrayTuple& arrays,
vtkm::cont::Token& token)
{
typename ExecutionTypes<DeviceTag>::PortalConstTuple portals;
ForEachArray::template PrepareForInput<DeviceTag>(arrays, portals);
ForEachArray::template PrepareForInput<DeviceTag>(arrays, portals, token);
return portals;
}
template <typename DeviceTag>
VTKM_CONT static const typename ExecutionTypes<DeviceTag>::PortalTuple PrepareForInPlace(
ArrayTuple& arrays)
ArrayTuple& arrays,
vtkm::cont::Token& token)
{
typename ExecutionTypes<DeviceTag>::PortalTuple portals;
ForEachArray::template PrepareForInPlace<DeviceTag>(arrays, portals);
ForEachArray::template PrepareForInPlace<DeviceTag>(arrays, portals, token);
return portals;
}
template <typename DeviceTag>
VTKM_CONT static const typename ExecutionTypes<DeviceTag>::PortalTuple PrepareForOutput(
ArrayTuple& arrays,
vtkm::Id numValues)
VTKM_CONT static const typename ExecutionTypes<DeviceTag>::PortalTuple
PrepareForOutput(ArrayTuple& arrays, vtkm::Id numValues, vtkm::cont::Token& token)
{
typename ExecutionTypes<DeviceTag>::PortalTuple portals;
ForEachArray::template PrepareForOutput<DeviceTag>(arrays, portals, numValues);
ForEachArray::template PrepareForOutput<DeviceTag>(arrays, portals, numValues, token);
return portals;
}
};
@ -479,15 +473,54 @@ private:
PortalTuple Portals;
};
template <typename ArrayTuple>
struct VTKM_ALWAYS_EXPORT StorageTagCompositeVector
} // namespace internal
template <typename... StorageTags>
struct VTKM_ALWAYS_EXPORT StorageTagCompositeVec
{
};
template <typename ArrayTuple>
class Storage<typename compvec::GetValueType<ArrayTuple>::ValueType,
StorageTagCompositeVector<ArrayTuple>>
namespace internal
{
template <typename ArrayTuple>
struct VTKM_ALWAYS_EXPORT VTKM_DEPRECATED(1.6, "Use StorageTagCompositeVec instead.")
StorageTagCompositeVector
{
};
template <typename... ArrayTs>
struct CompositeVectorTraits
{
// Need to check this here, since this traits struct is used in the
// ArrayHandleCompositeVector superclass definition before any other
// static_asserts could be used.
VTKM_STATIC_ASSERT_MSG(compvec::AllAreArrayHandles<ArrayTs...>::Value,
"Template parameters for ArrayHandleCompositeVector "
"must be a list of ArrayHandle types.");
using ValueType = typename compvec::GetValueType<vtkmstd::tuple<ArrayTs...>>::ValueType;
using StorageTag = vtkm::cont::StorageTagCompositeVec<typename ArrayTs::StorageTag...>;
using StorageType = Storage<ValueType, StorageTag>;
using Superclass = ArrayHandle<ValueType, StorageTag>;
};
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename... Arrays>
class Storage<typename compvec::GetValueType<vtkmstd::tuple<Arrays...>>::ValueType,
StorageTagCompositeVector<vtkmstd::tuple<Arrays...>>>
: CompositeVectorTraits<Arrays...>::StorageType
{
using Superclass = typename CompositeVectorTraits<Arrays...>::StorageType;
using Superclass::Superclass;
};
VTKM_DEPRECATED_SUPPRESS_END
template <typename T, typename... StorageTags>
class Storage<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags))>,
vtkm::cont::StorageTagCompositeVec<StorageTags...>>
{
using ArrayTuple = vtkmstd::tuple<vtkm::cont::ArrayHandle<T, StorageTags>...>;
using ForEachArray =
compvec::ArrayTupleForEach<0, vtkmstd::tuple_size<ArrayTuple>::value, ArrayTuple>;
using PortalTypes = compvec::PortalTupleTraits<ArrayTuple>;
@ -517,6 +550,18 @@ public:
}
}
template <typename... ArrayTypes>
VTKM_CONT Storage(const ArrayTypes&... arrays)
: Arrays(arrays...)
, Valid(true)
{
using SizeValidator = compvec::ArraySizeValidator<ArrayTuple>;
if (!SizeValidator::Exec(this->Arrays, this->GetNumberOfValues()))
{
throw ErrorBadValue("All arrays must have the same number of values.");
}
}
VTKM_CONT
PortalType GetPortal()
{
@ -578,20 +623,39 @@ private:
bool Valid;
};
template <typename ArrayTuple, typename DeviceTag>
class ArrayTransfer<typename compvec::GetValueType<ArrayTuple>::ValueType,
StorageTagCompositeVector<ArrayTuple>,
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename... Arrays, typename DeviceTag>
struct ArrayTransfer<typename compvec::GetValueType<vtkmstd::tuple<Arrays...>>::ValueType,
StorageTagCompositeVector<vtkmstd::tuple<Arrays...>>,
DeviceTag>
: ArrayTransfer<typename compvec::GetValueType<vtkmstd::tuple<Arrays...>>::ValueType,
typename CompositeVectorTraits<Arrays...>::StorageType,
DeviceTag>
{
using Superclass =
ArrayTransfer<typename compvec::GetValueType<vtkmstd::tuple<Arrays...>>::ValueType,
typename CompositeVectorTraits<Arrays...>::StorageType,
DeviceTag>;
using Superclass::Superclass;
};
VTKM_DEPRECATED_SUPPRESS_END
template <typename T, typename... StorageTags, typename DeviceTag>
class ArrayTransfer<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags))>,
vtkm::cont::StorageTagCompositeVec<StorageTags...>,
DeviceTag>
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceTag);
using ArrayTuple = vtkmstd::tuple<vtkm::cont::ArrayHandle<T, StorageTags>...>;
public:
using ValueType = typename compvec::GetValueType<ArrayTuple>::ValueType;
private:
using ForEachArray =
compvec::ArrayTupleForEach<0, vtkmstd::tuple_size<ArrayTuple>::value, ArrayTuple>;
using StorageTag = StorageTagCompositeVector<ArrayTuple>;
using StorageTag = vtkm::cont::StorageTagCompositeVec<StorageTags...>;
using StorageType = internal::Storage<ValueType, StorageTag>;
using ControlTraits = compvec::PortalTupleTraits<ArrayTuple>;
using ExecutionTraits = typename ControlTraits::template ExecutionTypes<DeviceTag>;
@ -614,24 +678,24 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) const
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token) const
{
return PortalConstExecution(
ControlTraits::template PrepareForInput<DeviceTag>(this->GetArrayTuple()));
ControlTraits::template PrepareForInput<DeviceTag>(this->GetArrayTuple(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(
ControlTraits::template PrepareForInPlace<DeviceTag>(this->GetArrayTuple()));
ControlTraits::template PrepareForInPlace<DeviceTag>(this->GetArrayTuple(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numValues)
PortalExecution PrepareForOutput(vtkm::Id numValues, vtkm::cont::Token& token)
{
return PortalExecution(
ControlTraits::template PrepareForOutput<DeviceTag>(this->GetArrayTuple(), numValues));
ControlTraits::template PrepareForOutput<DeviceTag>(this->GetArrayTuple(), numValues, token));
}
VTKM_CONT
@ -656,22 +720,6 @@ private:
StorageType* Storage;
};
template <typename... ArrayTs>
struct CompositeVectorTraits
{
// Need to check this here, since this traits struct is used in the
// ArrayHandleCompositeVector superclass definition before any other
// static_asserts could be used.
VTKM_STATIC_ASSERT_MSG(compvec::AllAreArrayHandles<ArrayTs...>::Value,
"Template parameters for ArrayHandleCompositeVector "
"must be a list of ArrayHandle types.");
using ValueType = typename compvec::GetValueType<vtkmstd::tuple<ArrayTs...>>::ValueType;
using StorageTag = StorageTagCompositeVector<vtkmstd::tuple<ArrayTs...>>;
using StorageType = Storage<ValueType, StorageTag>;
using Superclass = ArrayHandle<ValueType, StorageTag>;
};
} // namespace internal
/// \brief An \c ArrayHandle that combines components from other arrays.
@ -704,7 +752,7 @@ public:
VTKM_CONT
ArrayHandleCompositeVector(const ArrayTs&... arrays)
: Superclass(StorageType(vtkmstd::make_tuple(arrays...)))
: Superclass(StorageType(arrays...))
{
}
};
@ -742,6 +790,16 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleCompositeVector<AHs...>>
}
};
template <typename T, typename... STs>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(STs))>,
vtkm::cont::StorageTagCompositeVec<STs...>>>
: SerializableTypeString<
vtkm::cont::ArrayHandleCompositeVector<vtkm::cont::ArrayHandle<T, STs>...>>
{
};
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename... AHs>
struct SerializableTypeString<vtkm::cont::ArrayHandle<
typename vtkm::cont::internal::compvec::GetValueType<vtkmstd::tuple<AHs...>>::ValueType,
@ -749,6 +807,7 @@ struct SerializableTypeString<vtkm::cont::ArrayHandle<
: SerializableTypeString<vtkm::cont::ArrayHandleCompositeVector<AHs...>>
{
};
VTKM_DEPRECATED_SUPPRESS_END
}
} // vtkm::cont
@ -831,6 +890,15 @@ public:
}
};
template <typename T, typename... STs>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(STs))>,
vtkm::cont::StorageTagCompositeVec<STs...>>>
: Serialization<vtkm::cont::ArrayHandleCompositeVector<vtkm::cont::ArrayHandle<T, STs>...>>
{
};
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename... AHs>
struct Serialization<vtkm::cont::ArrayHandle<
typename vtkm::cont::internal::compvec::GetValueType<vtkmstd::tuple<AHs...>>::ValueType,
@ -838,6 +906,7 @@ struct Serialization<vtkm::cont::ArrayHandle<
: Serialization<vtkm::cont::ArrayHandleCompositeVector<AHs...>>
{
};
VTKM_DEPRECATED_SUPPRESS_END
} // diy
/// @endcond SERIALIZATION

@ -10,6 +10,9 @@
#ifndef vtk_m_cont_ArrayHandleConcatenate_h
#define vtk_m_cont_ArrayHandleConcatenate_h
#include <vtkm/Deprecated.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/cont/ArrayHandle.h>
namespace vtkm
@ -37,6 +40,7 @@ public:
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalConcatenate(const PortalType1& p1, const PortalType2& p2)
: portal1(p1)
@ -45,6 +49,7 @@ public:
}
// Copy constructor
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename OtherP1, typename OtherP2>
VTKM_EXEC_CONT ArrayPortalConcatenate(const ArrayPortalConcatenate<OtherP1, OtherP2>& src)
: portal1(src.GetPortal1())
@ -98,24 +103,64 @@ private:
} // namespace internal
template <typename ArrayHandleType1, typename ArrayHandleType2>
class StorageTagConcatenate
template <typename StorageTag1, typename StorageTag2>
class VTKM_ALWAYS_EXPORT StorageTagConcatenate
{
};
namespace internal
{
template <typename ArrayHandleType1, typename ArrayHandleType2>
class Storage<typename ArrayHandleType1::ValueType,
StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>
namespace detail
{
template <typename T, typename ArrayOrStorage, bool IsArrayType>
struct ConcatinateTypeArgImpl;
template <typename T, typename Storage>
struct ConcatinateTypeArgImpl<T, Storage, false>
{
using StorageTag = Storage;
using ArrayHandle = vtkm::cont::ArrayHandle<T, StorageTag>;
};
template <typename T, typename Array>
struct ConcatinateTypeArgImpl<T, Array, true>
{
VTKM_STATIC_ASSERT_MSG((std::is_same<T, typename Array::ValueType>::value),
"Used array with wrong type in ArrayHandleConcatinate.");
using StorageTag VTKM_DEPRECATED(
1.6,
"Use storage tags instead of array handles in StorageTagConcatenate.") =
typename Array::StorageTag;
using ArrayHandle VTKM_DEPRECATED(
1.6,
"Use storage tags instead of array handles in StorageTagConcatenate.") =
vtkm::cont::ArrayHandle<T, typename Array::StorageTag>;
};
template <typename T, typename ArrayOrStorage>
struct ConcatinateTypeArg
: ConcatinateTypeArgImpl<T,
ArrayOrStorage,
vtkm::cont::internal::ArrayHandleCheck<ArrayOrStorage>::type::value>
{
};
} // namespace detail
template <typename T, typename ST1, typename ST2>
class Storage<T, StorageTagConcatenate<ST1, ST2>>
{
using ArrayHandleType1 = typename detail::ConcatinateTypeArg<T, ST1>::ArrayHandle;
using ArrayHandleType2 = typename detail::ConcatinateTypeArg<T, ST2>::ArrayHandle;
public:
using ValueType = typename ArrayHandleType1::ValueType;
using PortalType = ArrayPortalConcatenate<typename ArrayHandleType1::PortalControl,
typename ArrayHandleType2::PortalControl>;
using PortalConstType = ArrayPortalConcatenate<typename ArrayHandleType1::PortalConstControl,
typename ArrayHandleType2::PortalConstControl>;
using ValueType = T;
using PortalType = ArrayPortalConcatenate<typename ArrayHandleType1::WritePortalType,
typename ArrayHandleType2::WritePortalType>;
using PortalConstType = ArrayPortalConcatenate<typename ArrayHandleType1::ReadPortalType,
typename ArrayHandleType2::ReadPortalType>;
VTKM_CONT
Storage()
@ -127,21 +172,22 @@ public:
Storage(const ArrayHandleType1& a1, const ArrayHandleType2& a2)
: array1(a1)
, array2(a2)
, valid(true){};
, valid(true)
{
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->valid);
return PortalConstType(this->array1.GetPortalConstControl(),
this->array2.GetPortalConstControl());
return PortalConstType(this->array1.ReadPortal(), this->array2.ReadPortal());
}
VTKM_CONT
PortalType GetPortal()
{
VTKM_ASSERT(this->valid);
return PortalType(this->array1.GetPortalControl(), this->array2.GetPortalControl());
return PortalType(this->array1.WritePortal(), this->array2.WritePortal());
}
VTKM_CONT
@ -198,16 +244,19 @@ private:
bool valid;
}; // class Storage
template <typename ArrayHandleType1, typename ArrayHandleType2, typename Device>
class ArrayTransfer<typename ArrayHandleType1::ValueType,
StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>,
Device>
template <typename T, typename ST1, typename ST2, typename Device>
class ArrayTransfer<T, StorageTagConcatenate<ST1, ST2>, Device>
{
using ArrayHandleType1 = typename detail::ConcatinateTypeArg<T, ST1>::ArrayHandle;
using ArrayHandleType2 = typename detail::ConcatinateTypeArg<T, ST2>::ArrayHandle;
using StorageTag1 = typename detail::ConcatinateTypeArg<T, ST1>::StorageTag;
using StorageTag2 = typename detail::ConcatinateTypeArg<T, ST2>::StorageTag;
public:
using ValueType = typename ArrayHandleType1::ValueType;
using ValueType = T;
private:
using StorageTag = StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>;
using StorageTag = StorageTagConcatenate<StorageTag1, StorageTag2>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
@ -235,21 +284,21 @@ public:
}
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->array1.PrepareForInput(Device()),
this->array2.PrepareForInput(Device()));
return PortalConstExecution(this->array1.PrepareForInput(Device(), token),
this->array2.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->array1.PrepareForInPlace(Device()),
this->array2.PrepareForInPlace(Device()));
return PortalExecution(this->array1.PrepareForInPlace(Device(), token),
this->array2.PrepareForInPlace(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues))
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorInternal("ArrayHandleConcatenate is derived and read-only. ");
}
@ -295,14 +344,16 @@ namespace cont
template <typename ArrayHandleType1, typename ArrayHandleType2>
class ArrayHandleConcatenate
: public vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,
StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>
StorageTagConcatenate<typename ArrayHandleType1::StorageTag,
typename ArrayHandleType2::StorageTag>>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleConcatenate,
(ArrayHandleConcatenate<ArrayHandleType1, ArrayHandleType2>),
(vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,
StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>));
StorageTagConcatenate<typename ArrayHandleType1::StorageTag,
typename ArrayHandleType2::StorageTag>>));
protected:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
@ -344,10 +395,12 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
}
};
template <typename AH1, typename AH2>
template <typename T, typename ST1, typename ST2>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<typename AH1::ValueType, vtkm::cont::StorageTagConcatenate<AH1, AH2>>>
: SerializableTypeString<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConcatenate<ST1, ST2>>>
: SerializableTypeString<vtkm::cont::ArrayHandleConcatenate<
typename internal::detail::ConcatinateTypeArg<T, ST1>::ArrayHandle,
typename internal::detail::ConcatinateTypeArg<T, ST2>::ArrayHandle>>
{
};
}
@ -383,10 +436,11 @@ public:
}
};
template <typename AH1, typename AH2>
struct Serialization<
vtkm::cont::ArrayHandle<typename AH1::ValueType, vtkm::cont::StorageTagConcatenate<AH1, AH2>>>
: Serialization<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
template <typename T, typename ST1, typename ST2>
struct Serialization<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConcatenate<ST1, ST2>>>
: Serialization<vtkm::cont::ArrayHandleConcatenate<
typename vtkm::cont::internal::detail::ConcatinateTypeArg<T, ST1>::ArrayHandle,
typename vtkm::cont::internal::detail::ConcatinateTypeArg<T, ST2>::ArrayHandle>>
{
};
} // diy

@ -17,7 +17,11 @@ namespace vtkm
namespace cont
{
namespace detail
struct VTKM_ALWAYS_EXPORT StorageTagConstant
{
};
namespace internal
{
template <typename ValueType>
@ -36,7 +40,26 @@ private:
ValueType Value;
};
} // namespace detail
template <typename T>
using StorageTagConstantSuperclass =
typename vtkm::cont::ArrayHandleImplicit<ConstantFunctor<T>>::StorageTag;
template <typename T>
struct Storage<T, vtkm::cont::StorageTagConstant> : Storage<T, StorageTagConstantSuperclass<T>>
{
using Superclass = Storage<T, StorageTagConstantSuperclass<T>>;
using Superclass::Superclass;
};
template <typename T, typename Device>
struct ArrayTransfer<T, vtkm::cont::StorageTagConstant, Device>
: ArrayTransfer<T, StorageTagConstantSuperclass<T>, Device>
{
using Superclass = ArrayTransfer<T, StorageTagConstantSuperclass<T>, Device>;
using Superclass::Superclass;
};
} // namespace internal
/// \brief An array handle with a constant value.
///
@ -47,16 +70,17 @@ private:
/// takes (almost) no memory.
///
template <typename T>
class ArrayHandleConstant : public vtkm::cont::ArrayHandleImplicit<detail::ConstantFunctor<T>>
class ArrayHandleConstant : public vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleConstant,
(ArrayHandleConstant<T>),
(vtkm::cont::ArrayHandleImplicit<detail::ConstantFunctor<T>>));
(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>));
VTKM_CONT
ArrayHandleConstant(T value, vtkm::Id numberOfValues = 0)
: Superclass(detail::ConstantFunctor<T>(value), numberOfValues)
: Superclass(
typename Superclass::ReadPortalType(internal::ConstantFunctor<T>(value), numberOfValues))
{
}
};
@ -82,18 +106,18 @@ namespace cont
{
template <typename T>
struct SerializableTypeString<vtkm::cont::detail::ConstantFunctor<T>>
struct SerializableTypeString<vtkm::cont::ArrayHandleConstant<T>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "AH_ConstantFunctor<" + SerializableTypeString<T>::Get() + ">";
static std::string name = "AH_Constant<" + SerializableTypeString<T>::Get() + ">";
return name;
}
};
template <typename T>
struct SerializableTypeString<vtkm::cont::ArrayHandleConstant<T>>
: SerializableTypeString<vtkm::cont::ArrayHandleImplicit<vtkm::cont::detail::ConstantFunctor<T>>>
struct SerializableTypeString<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>>
: SerializableTypeString<vtkm::cont::ArrayHandleConstant<T>>
{
};
}
@ -104,7 +128,33 @@ namespace mangled_diy_namespace
template <typename T>
struct Serialization<vtkm::cont::ArrayHandleConstant<T>>
: Serialization<vtkm::cont::ArrayHandleImplicit<vtkm::cont::detail::ConstantFunctor<T>>>
{
private:
using Type = vtkm::cont::ArrayHandleConstant<T>;
using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
vtkmdiy::save(bb, obj.GetNumberOfValues());
vtkmdiy::save(bb, obj.ReadPortal().Get(0));
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
{
vtkm::Id count = 0;
vtkmdiy::load(bb, count);
T value;
vtkmdiy::load(bb, value);
obj = vtkm::cont::make_ArrayHandleConstant(value, count);
}
};
template <typename T>
struct Serialization<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>>
: Serialization<vtkm::cont::ArrayHandleConstant<T>>
{
};

@ -20,6 +20,10 @@ namespace vtkm
namespace cont
{
struct VTKM_ALWAYS_EXPORT StorageTagCounting
{
};
namespace internal
{
@ -87,12 +91,23 @@ private:
vtkm::Id NumberOfValues;
};
/// A convenience class that provides a typedef to the appropriate tag for
/// a counting storage.
template <typename ValueType>
struct ArrayHandleCountingTraits
template <typename T>
using StorageTagCountingSuperclass =
vtkm::cont::StorageTagImplicit<internal::ArrayPortalCounting<T>>;
template <typename T>
struct Storage<T, vtkm::cont::StorageTagCounting> : Storage<T, StorageTagCountingSuperclass<T>>
{
using Tag = vtkm::cont::StorageTagImplicit<vtkm::cont::internal::ArrayPortalCounting<ValueType>>;
using Superclass = Storage<T, StorageTagCountingSuperclass<T>>;
using Superclass::Superclass;
};
template <typename T, typename Device>
struct ArrayTransfer<T, vtkm::cont::StorageTagCounting, Device>
: ArrayTransfer<T, StorageTagCountingSuperclass<T>, Device>
{
using Superclass = ArrayTransfer<T, StorageTagCountingSuperclass<T>, Device>;
using Superclass::Superclass;
};
} // namespace internal
@ -101,21 +116,17 @@ struct ArrayHandleCountingTraits
/// contains a increment value, that is increment for each step between zero
/// and the passed in length
template <typename CountingValueType>
class ArrayHandleCounting : public vtkm::cont::ArrayHandle<
CountingValueType,
typename internal::ArrayHandleCountingTraits<CountingValueType>::Tag>
class ArrayHandleCounting
: public vtkm::cont::ArrayHandle<CountingValueType, vtkm::cont::StorageTagCounting>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleCounting,
(ArrayHandleCounting<CountingValueType>),
(vtkm::cont::ArrayHandle<
CountingValueType,
typename internal::ArrayHandleCountingTraits<CountingValueType>::Tag>));
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleCounting,
(ArrayHandleCounting<CountingValueType>),
(vtkm::cont::ArrayHandle<CountingValueType, StorageTagCounting>));
VTKM_CONT
ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm::Id length)
: Superclass(typename Superclass::PortalConstControl(start, step, length))
: Superclass(typename Superclass::ReadPortalType(start, step, length))
{
}
};
@ -150,8 +161,7 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleCounting<T>>
};
template <typename T>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<T, typename vtkm::cont::ArrayHandleCounting<T>::StorageTag>>
struct SerializableTypeString<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>>
: SerializableTypeString<vtkm::cont::ArrayHandleCounting<T>>
{
};
@ -171,7 +181,7 @@ private:
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
auto portal = obj.GetPortalConstControl();
auto portal = obj.ReadPortal();
vtkmdiy::save(bb, portal.GetStart());
vtkmdiy::save(bb, portal.GetStep());
vtkmdiy::save(bb, portal.GetNumberOfValues());
@ -191,8 +201,7 @@ public:
};
template <typename T>
struct Serialization<
vtkm::cont::ArrayHandle<T, typename vtkm::cont::ArrayHandleCounting<T>::StorageTag>>
struct Serialization<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>>
: Serialization<vtkm::cont::ArrayHandleCounting<T>>
{
};

@ -11,6 +11,7 @@
#define vtk_m_ArrayHandleDecorator_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/Storage.h>
#include <vtkm/StaticAssert.h>
@ -26,11 +27,15 @@
#include <type_traits>
#include <utility>
// MSVC and CUDA and Xcode < 10 and Clang < 5 have issues with tao integer sequences
#if defined(VTKM_MSVC) || defined(VTKM_CUDA_DEVICE_PASS) || \
(defined(__apple_build_version__) && (__apple_build_version__ < 10000000)) || \
(defined(VTKM_CLANG) && (__clang_major__ < 5))
#define VTKM_USE_BRIGAND_SEQ
// Some compilers like brigand's integer sequences.
// Some compilers prefer tao's.
// Brigand seems to have more support, so we'll use that as default and fallback
// to tao when brigand fails. With C++14, we'll be able to just use the STL.
#if !defined(VTKM_CUDA_DEVICE_PASS) && \
(defined(VTKM_GCC) || \
(defined(__apple_build_version__) && (__apple_build_version__ >= 10000000)) || \
(defined(VTKM_CLANG) && (__clang_major__ >= 5)))
#define VTKM_USE_TAO_SEQ
#endif
namespace vtkm
@ -121,11 +126,9 @@ template <typename DecoratorImplT, template <typename...> class List, typename..
struct IsFunctorInvertibleImpl<DecoratorImplT, List<PortalTs...>>
{
private:
using PortalList = brigand::list<typename std::decay<PortalTs>::type...>;
template <
typename T,
typename U = decltype(std::declval<T>().CreateInverseFunctor(std::declval<PortalTs>()...))>
typename U = decltype(std::declval<T>().CreateInverseFunctor(std::declval<PortalTs&&>()...))>
static std::true_type InverseExistsTest(int);
template <typename T>
@ -135,6 +138,44 @@ public:
using type = decltype(InverseExistsTest<DecoratorImplT>(0));
};
// Tests whether DecoratorImplT has an AllocateSourceArrays(size, Arrays...) method.
template <typename DecoratorImplT, typename ArrayList>
struct IsDecoratorAllocatableImpl;
template <typename DecoratorImplT, template <typename...> class List, typename... ArrayTs>
struct IsDecoratorAllocatableImpl<DecoratorImplT, List<ArrayTs...>>
{
private:
template <
typename T,
typename U = decltype(std::declval<T>().AllocateSourceArrays(0, std::declval<ArrayTs&>()...))>
static std::true_type Exists(int);
template <typename T>
static std::false_type Exists(...);
public:
using type = decltype(Exists<DecoratorImplT>(0));
};
// Tests whether DecoratorImplT has a ShrinkSourceArrays(size, Arrays...) method.
template <typename DecoratorImplT, typename ArrayList>
struct IsDecoratorShrinkableImpl;
template <typename DecoratorImplT, template <typename...> class List, typename... ArrayTs>
struct IsDecoratorShrinkableImpl<DecoratorImplT, List<ArrayTs...>>
{
private:
template <
typename T,
typename U = decltype(std::declval<T>().ShrinkSourceArrays(0, std::declval<ArrayTs&>()...))>
static std::true_type Exists(int);
template <typename T>
static std::false_type Exists(...);
public:
using type = decltype(Exists<DecoratorImplT>(0));
};
// Deduces the type returned by DecoratorImplT::CreateFunctor when given
// the specified portals.
template <typename DecoratorImplT, typename PortalList>
@ -143,7 +184,8 @@ struct GetFunctorTypeImpl;
template <typename DecoratorImplT, template <typename...> class List, typename... PortalTs>
struct GetFunctorTypeImpl<DecoratorImplT, List<PortalTs...>>
{
using type = decltype(std::declval<DecoratorImplT>().CreateFunctor(std::declval<PortalTs>()...));
using type =
decltype(std::declval<DecoratorImplT>().CreateFunctor(std::declval<PortalTs&&>()...));
};
// Deduces the type returned by DecoratorImplT::CreateInverseFunctor when given
@ -156,7 +198,7 @@ template <typename DecoratorImplT, template <typename...> class List, typename..
struct GetInverseFunctorTypeImpl<std::true_type, DecoratorImplT, List<PortalTs...>>
{
using type =
decltype(std::declval<DecoratorImplT>().CreateInverseFunctor(std::declval<PortalTs>()...));
decltype(std::declval<DecoratorImplT>().CreateInverseFunctor(std::declval<PortalTs&&>()...));
};
template <typename DecoratorImplT, typename PortalList>
@ -169,49 +211,49 @@ struct GetInverseFunctorTypeImpl<std::false_type, DecoratorImplT, PortalList>
// See note below about using non-writable portals in invertible functors.
// We need to sub in const portals when writable ones don't exist.
template <typename ArrayT>
typename std::decay<ArrayT>::type::PortalControl GetPortalControlImpl(std::true_type,
ArrayT&& array)
typename std::decay<ArrayT>::type::WritePortalType GetPortalControlImpl(std::true_type,
ArrayT&& array)
{
return array.GetPortalControl();
return array.WritePortal();
}
template <typename ArrayT>
typename std::decay<ArrayT>::type::PortalConstControl GetPortalControlImpl(std::false_type,
ArrayT&& array)
typename std::decay<ArrayT>::type::ReadPortalType GetPortalControlImpl(std::false_type,
ArrayT&& array)
{
return array.GetPortalConstControl();
return array.ReadPortal();
}
template <typename ArrayT, typename Device>
typename std::decay<ArrayT>::type::template ExecutionTypes<Device>::Portal
GetPortalInPlaceImpl(std::true_type, ArrayT&& array, Device)
GetPortalInPlaceImpl(std::true_type, ArrayT&& array, Device, vtkm::cont::Token& token)
{
return array.PrepareForInPlace(Device{});
return array.PrepareForInPlace(Device{}, token);
}
template <typename ArrayT, typename Device>
typename std::decay<ArrayT>::type::template ExecutionTypes<Device>::PortalConst
GetPortalInPlaceImpl(std::false_type, ArrayT&& array, Device)
GetPortalInPlaceImpl(std::false_type, ArrayT&& array, Device, vtkm::cont::Token& token)
{
// ArrayT is read-only -- prepare for input instead.
return array.PrepareForInput(Device{});
return array.PrepareForInput(Device{}, token);
}
template <typename ArrayT, typename Device>
typename std::decay<ArrayT>::type::template ExecutionTypes<Device>::Portal
GetPortalOutputImpl(std::true_type, ArrayT&& array, Device)
GetPortalOutputImpl(std::true_type, ArrayT&& array, Device, vtkm::cont::Token& token)
{
// Prepare these for inplace usage instead -- we'll likely need to read
// from these in addition to writing.
return array.PrepareForInPlace(Device{});
return array.PrepareForInPlace(Device{}, token);
}
template <typename ArrayT, typename Device>
typename std::decay<ArrayT>::type::template ExecutionTypes<Device>::PortalConst
GetPortalOutputImpl(std::false_type, ArrayT&& array, Device)
GetPortalOutputImpl(std::false_type, ArrayT&& array, Device, vtkm::cont::Token& token)
{
// ArrayT is read-only -- prepare for input instead.
return array.PrepareForInput(Device{});
return array.PrepareForInput(Device{}, token);
}
} // namespace detail
@ -223,13 +265,13 @@ GetPortalOutputImpl(std::false_type, ArrayT&& array, Device)
// const array handles so we can at least read from them in the inverse
// functors.
template <typename ArrayT,
typename Portal = typename std::decay<ArrayT>::type::PortalControl,
typename PortalConst = typename std::decay<ArrayT>::type::PortalConstControl>
typename Portal = typename std::decay<ArrayT>::type::WritePortalType,
typename PortalConst = typename std::decay<ArrayT>::type::ReadPortalType>
using GetPortalControlType =
typename brigand::if_<vtkm::internal::PortalSupportsSets<Portal>, Portal, PortalConst>::type;
template <typename ArrayT>
using GetPortalConstControlType = typename std::decay<ArrayT>::type::PortalConstControl;
using GetPortalConstControlType = typename std::decay<ArrayT>::type::ReadPortalType;
template <typename ArrayT,
typename Device,
@ -247,40 +289,38 @@ using GetPortalConstExecutionType =
// Get portal objects:
// See note above -- we swap in const portals sometimes.
template <typename ArrayT>
GetPortalControlType<typename std::decay<ArrayT>::type> GetPortalControl(ArrayT&& array)
GetPortalControlType<typename std::decay<ArrayT>::type> WritePortal(ArrayT&& array)
{
return detail::GetPortalControlImpl(IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array));
}
template <typename ArrayT>
GetPortalConstControlType<typename std::decay<ArrayT>::type> GetPortalConstControl(
const ArrayT& array)
GetPortalConstControlType<typename std::decay<ArrayT>::type> ReadPortal(const ArrayT& array)
{
return array.GetPortalConstControl();
return array.ReadPortal();
}
template <typename ArrayT, typename Device>
GetPortalConstExecutionType<typename std::decay<ArrayT>::type, Device> GetPortalInput(
const ArrayT& array,
Device)
GetPortalConstExecutionType<typename std::decay<ArrayT>::type, Device>
GetPortalInput(const ArrayT& array, Device, vtkm::cont::Token& token)
{
return array.PrepareForInput(Device{});
return array.PrepareForInput(Device{}, token);
}
template <typename ArrayT, typename Device>
GetPortalExecutionType<typename std::decay<ArrayT>::type, Device> GetPortalInPlace(ArrayT&& array,
Device)
GetPortalExecutionType<typename std::decay<ArrayT>::type, Device>
GetPortalInPlace(ArrayT&& array, Device, vtkm::cont::Token& token)
{
return detail::GetPortalInPlaceImpl(
IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array), Device{});
IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array), Device{}, token);
}
template <typename ArrayT, typename Device>
GetPortalExecutionType<typename std::decay<ArrayT>::type, Device> GetPortalOutput(ArrayT&& array,
Device)
GetPortalExecutionType<typename std::decay<ArrayT>::type, Device>
GetPortalOutput(ArrayT&& array, Device, vtkm::cont::Token& token)
{
return detail::GetPortalOutputImpl(
IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array), Device{});
IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array), Device{}, token);
}
// Equivalent to std::true_type if *any* portal in PortalList can be written to.
@ -296,6 +336,18 @@ template <typename DecoratorImplT, typename PortalList>
using IsFunctorInvertible =
typename detail::IsFunctorInvertibleImpl<DecoratorImplT, PortalList>::type;
// Set to std::true_type if DecoratorImplT::AllocateSourceArrays can be called
// with the supplied arrays, or std::false_type otherwise.
template <typename DecoratorImplT, typename ArrayList>
using IsDecoratorAllocatable =
typename detail::IsDecoratorAllocatableImpl<DecoratorImplT, ArrayList>::type;
// Set to std::true_type if DecoratorImplT::ShrinkSourceArrays can be called
// with the supplied arrays, or std::false_type otherwise.
template <typename DecoratorImplT, typename ArrayList>
using IsDecoratorShrinkable =
typename detail::IsDecoratorShrinkableImpl<DecoratorImplT, ArrayList>::type;
// std::true_type/std::false_type depending on whether the decorator impl has a
// CreateInversePortal method AND any of the arrays are writable.
template <typename DecoratorImplT, typename PortalList>
@ -324,19 +376,18 @@ using GetInverseFunctorType =
// - So we jump through some decltype/declval hoops here to get this to work:
template <typename... ArrayTs>
using GetPortalConstControlList =
brigand::list<decltype((GetPortalConstControl(std::declval<ArrayTs>())))...>;
brigand::list<decltype((ReadPortal(std::declval<ArrayTs&>())))...>;
template <typename Device, typename... ArrayTs>
using GetPortalConstExecutionList =
brigand::list<decltype((GetPortalInput(std::declval<ArrayTs>(), Device{})))...>;
using GetPortalConstExecutionList = brigand::list<decltype(
(GetPortalInput(std::declval<ArrayTs&>(), Device{}, std::declval<vtkm::cont::Token&>())))...>;
template <typename... ArrayTs>
using GetPortalControlList =
brigand::list<decltype((GetPortalControl(std::declval<ArrayTs>())))...>;
using GetPortalControlList = brigand::list<decltype((WritePortal(std::declval<ArrayTs&>())))...>;
template <typename Device, typename... ArrayTs>
using GetPortalExecutionList =
brigand::list<decltype((GetPortalInPlace(std::declval<ArrayTs>(), Device{})))...>;
using GetPortalExecutionList = brigand::list<decltype(
(GetPortalInPlace(std::declval<ArrayTs&>(), Device{}, std::declval<vtkm::cont::Token&>())))...>;
template <typename DecoratorImplT, typename... ArrayTs>
struct DecoratorStorageTraits
@ -359,11 +410,15 @@ struct DecoratorStorageTraits
using ArrayTupleType = vtkmstd::tuple<ArrayTs...>;
// size_t integral constants that index ArrayTs:
#ifdef VTKM_USE_BRIGAND_SEQ
#ifndef VTKM_USE_TAO_SEQ
using IndexList = brigand::make_sequence<brigand::size_t<0>, sizeof...(ArrayTs)>;
#else // VTKM_USE_BRIGAND_SEQ
#else // VTKM_USE_TAO_SEQ
using IndexList = tao::seq::make_index_sequence<sizeof...(ArrayTs)>;
#endif // VTKM_USE_BRIGAND_SEQ
#endif // VTKM_USE_TAO_SEQ
// true_type/false_type depending on whether the decorator supports Allocate/Shrink:
using IsAllocatable = IsDecoratorAllocatable<DecoratorImplT, ArrayList>;
using IsShrinkable = IsDecoratorShrinkable<DecoratorImplT, ArrayList>;
// Portal lists:
// NOTE we have to pass the parameter pack here instead of using ArrayList
@ -442,7 +497,42 @@ struct DecoratorStorageTraits
return { impl.CreateFunctor(portals...), impl.CreateInverseFunctor(portals...), numVals };
}
#ifdef VTKM_USE_BRIGAND_SEQ
// Static dispatch for calling AllocateSourceArrays on supported implementations:
VTKM_CONT[[noreturn]] static void CallAllocate(std::false_type,
const DecoratorImplT&,
vtkm::Id,
ArrayTs&...)
{
throw vtkm::cont::ErrorBadType("Allocate not supported by this ArrayHandleDecorator.");
}
VTKM_CONT static void CallAllocate(std::true_type,
const DecoratorImplT& impl,
vtkm::Id newSize,
ArrayTs&... arrays)
{
impl.AllocateSourceArrays(newSize, arrays...);
}
// Static dispatch for calling ShrinkSourceArrays on supported implementations.
VTKM_CONT[[noreturn]] static void CallShrink(std::false_type,
const DecoratorImplT&,
vtkm::Id,
ArrayTs&...)
{
throw vtkm::cont::ErrorBadType("Shrink not supported by this ArrayHandleDecorator.");
}
VTKM_CONT static void CallShrink(std::true_type,
const DecoratorImplT& impl,
vtkm::Id newSize,
ArrayTs&... arrays)
{
impl.ShrinkSourceArrays(newSize, arrays...);
}
#ifndef VTKM_USE_TAO_SEQ
// Portal construction methods. These actually create portals.
template <template <typename...> class List, typename... Indices>
VTKM_CONT static PortalControlType MakePortalControl(const DecoratorImplT& impl,
@ -461,7 +551,7 @@ struct DecoratorStorageTraits
// Indices{}.value : Works on both MSVC2015 and MSVC2017.
//
// Don't touch the following line unless you really, really have to.
GetPortalControl(vtkmstd::get<Indices{}.value>(arrays))...);
WritePortal(vtkmstd::get<Indices{}.value>(arrays))...);
}
template <template <typename...> class List, typename... Indices>
@ -475,7 +565,7 @@ struct DecoratorStorageTraits
impl,
// Don't touch the following line unless you really, really have to. See
// note in MakePortalControl.
GetPortalConstControl(vtkmstd::get<Indices{}.value>(arrays))...);
ReadPortal(vtkmstd::get<Indices{}.value>(arrays))...);
}
template <template <typename...> class List, typename... Indices, typename Device>
@ -483,14 +573,15 @@ struct DecoratorStorageTraits
const ArrayTupleType& arrays,
vtkm::Id numValues,
List<Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalConstExecutionType<Device>>(
numValues,
impl,
// Don't touch the following line unless you really, really have to. See
// note in MakePortalControl.
GetPortalInput(vtkmstd::get<Indices{}.value>(arrays), dev)...);
GetPortalInput(vtkmstd::get<Indices{}.value>(arrays), dev, token)...);
}
template <template <typename...> class List, typename... Indices, typename Device>
@ -498,14 +589,15 @@ struct DecoratorStorageTraits
ArrayTupleType& arrays,
vtkm::Id numValues,
List<Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues,
impl,
// Don't touch the following line unless you really, really have to. See
// note in MakePortalControl.
GetPortalInPlace(vtkmstd::get<Indices{}.value>(arrays), dev)...);
GetPortalInPlace(vtkmstd::get<Indices{}.value>(arrays), dev, token)...);
}
template <template <typename...> class List, typename... Indices, typename Device>
@ -513,17 +605,37 @@ struct DecoratorStorageTraits
ArrayTupleType& arrays,
vtkm::Id numValues,
List<Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues,
impl,
// Don't touch the following line unless you really, really have to. See
// note in MakePortalControl.
GetPortalOutput(vtkmstd::get<Indices{}.value>(arrays), dev)...);
GetPortalOutput(vtkmstd::get<Indices{}.value>(arrays), dev, token)...);
}
#else // VTKM_USE_BRIGAND_SEQ
template <template <typename...> class List, typename... Indices>
VTKM_CONT static void AllocateSourceArrays(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<Indices...>)
{
CallAllocate(IsAllocatable{}, impl, numValues, vtkmstd::get<Indices{}.value>(arrays)...);
}
template <template <typename...> class List, typename... Indices>
VTKM_CONT static void ShrinkSourceArrays(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<Indices...>)
{
CallShrink(IsShrinkable{}, impl, numValues, vtkmstd::get<Indices{}.value>(arrays)...);
}
#else // VTKM_USE_TAO_SEQ
// Portal construction methods. These actually create portals.
template <template <typename, std::size_t...> class List, std::size_t... Indices>
VTKM_CONT static PortalControlType MakePortalControl(const DecoratorImplT& impl,
@ -532,7 +644,7 @@ struct DecoratorStorageTraits
List<std::size_t, Indices...>)
{
return CreatePortalDecorator<PortalControlType>(
numValues, impl, GetPortalControl(vtkmstd::get<Indices>(arrays))...);
numValues, impl, WritePortal(vtkmstd::get<Indices>(arrays))...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices>
@ -542,7 +654,7 @@ struct DecoratorStorageTraits
List<std::size_t, Indices...>)
{
return CreatePortalDecorator<PortalConstControlType>(
numValues, impl, GetPortalConstControl(vtkmstd::get<Indices>(arrays))...);
numValues, impl, ReadPortal(vtkmstd::get<Indices>(arrays))...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
@ -550,10 +662,11 @@ struct DecoratorStorageTraits
const ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalConstExecutionType<Device>>(
numValues, impl, GetPortalInput(vtkmstd::get<Indices>(arrays), dev)...);
numValues, impl, GetPortalInput(vtkmstd::get<Indices>(arrays), dev, token)...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
@ -561,10 +674,11 @@ struct DecoratorStorageTraits
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues, impl, GetPortalInPlace(vtkmstd::get<Indices>(arrays), dev)...);
numValues, impl, GetPortalInPlace(vtkmstd::get<Indices>(arrays), dev, token)...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
@ -572,12 +686,32 @@ struct DecoratorStorageTraits
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
Device dev,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues, impl, GetPortalOutput(vtkmstd::get<Indices>(arrays), dev)...);
numValues, impl, GetPortalOutput(vtkmstd::get<Indices>(arrays), dev, token)...);
}
#endif // VTKM_USE_BRIGAND_SEQ
template <template <typename, std::size_t...> class List, std::size_t... Indices>
VTKM_CONT static void AllocateSourceArrays(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>)
{
CallAllocate(IsAllocatable{}, impl, numValues, vtkmstd::get<Indices>(arrays)...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices>
VTKM_CONT static void ShrinkSourceArrays(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>)
{
CallShrink(IsShrinkable{}, impl, numValues, vtkmstd::get<Indices>(arrays)...);
}
#endif // VTKM_USE_TAO_SEQ
};
} // end namespace decor
@ -639,18 +773,21 @@ public:
}
VTKM_CONT
void Allocate(vtkm::Id)
void Allocate(vtkm::Id numValues)
{
VTKM_ASSERT(this->Valid);
// No-op. I suppose eventually we could pass numValues down to the
// implementation class and let it do something intelligent.
Traits::AllocateSourceArrays(this->Implementation, this->ArrayTuple, numValues, IndexList{});
// If the above call doesn't throw, update our state.
this->NumberOfValues = numValues;
}
VTKM_CONT
void Shrink(vtkm::Id)
void Shrink(vtkm::Id numValues)
{
VTKM_ASSERT(this->Valid);
// No-op. Again, could eventually be passed down to the implementation.
Traits::ShrinkSourceArrays(this->Implementation, this->ArrayTuple, numValues, IndexList{});
// If the above call doesn't throw, update our state.
this->NumberOfValues = numValues;
}
VTKM_CONT
@ -737,33 +874,36 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) const
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token) const
{
return Traits::MakePortalInput(this->Storage->GetImplementation(),
this->Storage->GetArrayTuple(),
this->Storage->GetNumberOfValues(),
IndexList{},
Device{});
Device{},
token);
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return Traits::MakePortalInPlace(this->Storage->GetImplementation(),
this->Storage->GetArrayTuple(),
this->Storage->GetNumberOfValues(),
IndexList{},
Device{});
Device{},
token);
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id)
PortalExecution PrepareForOutput(vtkm::Id, vtkm::cont::Token& token)
{
return Traits::MakePortalOutput(this->Storage->GetImplementation(),
this->Storage->GetArrayTuple(),
this->Storage->GetNumberOfValues(),
IndexList{},
Device{});
Device{},
token);
}
VTKM_CONT
@ -775,10 +915,7 @@ public:
}
VTKM_CONT
void Shrink(vtkm::Id)
{
// no-op
}
void Shrink(vtkm::Id numValues) { this->Storage->Shrink(numValues); }
VTKM_CONT
@ -809,7 +946,7 @@ private:
/// // Takes one portal for each source array handle (only two shown).
/// // Returns a functor that defines:
/// //
/// // ValueType operator()(vtkm::Id id) const;
/// // VTKM_EXEC_CONT ValueType operator()(vtkm::Id id) const;
/// //
/// // which takes an index and returns a value which should be produced by
/// // the source arrays somehow. This ValueType will be the ValueType of the
@ -818,12 +955,13 @@ private:
/// // Both SomeFunctor::operator() and CreateFunctor must be const.
/// //
/// template <typename Portal1Type, typename Portal2Type>
/// VTKM_CONT
/// SomeFunctor CreateFunctor(Portal1Type portal1, Portal2Type portal2) const;
///
/// // Takes one portal for each source array handle (only two shown).
/// // Returns a functor that defines:
/// //
/// // void operator()(vtkm::Id id, ValueType val) const;
/// // VTKM_EXEC_CONT void operator()(vtkm::Id id, ValueType val) const;
/// //
/// // which takes an index and a value, which should be used to modify one
/// // or more of the source arrays.
@ -837,9 +975,35 @@ private:
/// // const.
/// //
/// template <typename Portal1Type, typename Portal2Type>
/// VTKM_CONT
/// SomeInverseFunctor CreateInverseFunctor(Portal1Type portal1,
/// Portal2Type portal2) const;
///
/// // Given a set of ArrayHandles and a size, implement what should happen
/// // to the source ArrayHandles when Allocate() is called on the decorator
/// // handle.
/// //
/// // AllocateSourceArrays is optional; if not provided, the
/// // ArrayHandleDecorator will throw if its Allocate method is called. If
/// // an implementation is present and doesn't throw, the
/// // ArrayHandleDecorator's internal state is updated to show `size` as the
/// // number of values.
/// template <typename Array1Type, typename Array2Type>
/// VTKM_CONT
/// void AllocateSourceArrays(vtkm::Id size, Array1Type array1, Array2Type array2) const;
///
/// // Given a set of ArrayHandles and a size, implement what should happen to
/// // the source ArrayHandles when Shrink() is called on the decorator handle.
/// //
/// // ShrinkSourceArrays is optional; if not provided, the
/// // ArrayHandleDecorator will throw if its Shrink method is called. If
/// // an implementation is present and doesn't throw, the
/// // ArrayHandleDecorator's internal state is updated to show `size` as the
/// // number of values.
/// template <typename Array1Type, typename Array2Type>
/// VTKM_CONT
/// void ShrinkSourceArrays(vtkm::Id size, Array1Type array1, Array2Type array2) const;
///
/// };
/// ```
///
@ -894,6 +1058,8 @@ make_ArrayHandleDecorator(vtkm::Id numValues, DecoratorImplT&& f, ArrayTs&&... a
}
} // namespace vtkm::cont
#undef VTKM_USE_BRIGAND_SEQ
#ifdef VTKM_USE_TAO_SEQ
#undef VTKM_USE_TAO_SEQ
#endif
#endif //vtk_m_ArrayHandleDecorator_h

@ -148,21 +148,21 @@ public:
}
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadValue("Input access not supported: "
"Cannot read from an ArrayHandleDiscard.");
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadValue("InPlace access not supported: "
"Cannot read from an ArrayHandleDiscard.");
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numValues)
PortalExecution PrepareForOutput(vtkm::Id numValues, vtkm::cont::Token&)
{
VTKM_ASSERT(this->Internal != nullptr);
this->Internal->Allocate(numValues);

@ -51,6 +51,9 @@ public:
{
}
ArrayPortalExtractComponent& operator=(const ArrayPortalExtractComponent& src) = default;
ArrayPortalExtractComponent& operator=(ArrayPortalExtractComponent&& src) = default;
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); }
@ -92,8 +95,8 @@ class Storage<typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::Com
StorageTagExtractComponent<ArrayHandleType>>
{
public:
using PortalType = ArrayPortalExtractComponent<typename ArrayHandleType::PortalControl>;
using PortalConstType = ArrayPortalExtractComponent<typename ArrayHandleType::PortalConstControl>;
using PortalType = ArrayPortalExtractComponent<typename ArrayHandleType::WritePortalType>;
using PortalConstType = ArrayPortalExtractComponent<typename ArrayHandleType::ReadPortalType>;
using ValueType = typename PortalType::ValueType;
VTKM_CONT
@ -116,14 +119,14 @@ public:
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(this->Array.GetPortalConstControl(), this->Component);
return PortalConstType(this->Array.ReadPortal(), this->Component);
}
VTKM_CONT
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->Array.GetPortalControl(), this->Component);
return PortalType(this->Array.WritePortal(), this->Component);
}
VTKM_CONT
@ -209,21 +212,22 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Component);
return PortalConstExecution(this->Array.PrepareForInput(Device(), token), this->Component);
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForInPlace(Device()), this->Component);
return PortalExecution(this->Array.PrepareForInPlace(Device(), token), this->Component);
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()), this->Component);
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device(), token),
this->Component);
}
VTKM_CONT

@ -109,28 +109,28 @@ namespace vtkm
namespace cont
{
namespace internal
{
template <typename SourceArrayHandleType, vtkm::IdComponent NUM_COMPONENTS>
template <typename SourceStorageTag, vtkm::IdComponent NUM_COMPONENTS>
struct VTKM_ALWAYS_EXPORT StorageTagGroupVec
{
};
template <typename SourceArrayHandleType, vtkm::IdComponent NUM_COMPONENTS>
class Storage<vtkm::Vec<typename SourceArrayHandleType::ValueType, NUM_COMPONENTS>,
vtkm::cont::internal::StorageTagGroupVec<SourceArrayHandleType, NUM_COMPONENTS>>
namespace internal
{
using ComponentType = typename SourceArrayHandleType::ValueType;
template <typename ComponentType, vtkm::IdComponent NUM_COMPONENTS, typename SourceStorageTag>
class Storage<vtkm::Vec<ComponentType, NUM_COMPONENTS>,
vtkm::cont::StorageTagGroupVec<SourceStorageTag, NUM_COMPONENTS>>
{
using SourceArrayHandleType = vtkm::cont::ArrayHandle<ComponentType, SourceStorageTag>;
public:
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
using PortalType =
vtkm::exec::internal::ArrayPortalGroupVec<typename SourceArrayHandleType::PortalControl,
vtkm::exec::internal::ArrayPortalGroupVec<typename SourceArrayHandleType::WritePortalType,
NUM_COMPONENTS>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalGroupVec<typename SourceArrayHandleType::PortalConstControl,
vtkm::exec::internal::ArrayPortalGroupVec<typename SourceArrayHandleType::ReadPortalType,
NUM_COMPONENTS>;
VTKM_CONT
@ -150,14 +150,14 @@ public:
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->SourceArray.GetPortalControl());
return PortalType(this->SourceArray.WritePortal());
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(this->SourceArray.GetPortalConstControl());
return PortalConstType(this->SourceArray.ReadPortal());
}
VTKM_CONT
@ -209,20 +209,23 @@ private:
bool Valid;
};
template <typename SourceArrayHandleType, vtkm::IdComponent NUM_COMPONENTS, typename Device>
class ArrayTransfer<vtkm::Vec<typename SourceArrayHandleType::ValueType, NUM_COMPONENTS>,
vtkm::cont::internal::StorageTagGroupVec<SourceArrayHandleType, NUM_COMPONENTS>,
template <typename ComponentType,
vtkm::IdComponent NUM_COMPONENTS,
typename SourceStorageTag,
typename Device>
class ArrayTransfer<vtkm::Vec<ComponentType, NUM_COMPONENTS>,
vtkm::cont::StorageTagGroupVec<SourceStorageTag, NUM_COMPONENTS>,
Device>
{
public:
using ComponentType = typename SourceArrayHandleType::ValueType;
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
private:
using StorageTag =
vtkm::cont::internal::StorageTagGroupVec<SourceArrayHandleType, NUM_COMPONENTS>;
using StorageTag = vtkm::cont::StorageTagGroupVec<SourceStorageTag, NUM_COMPONENTS>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using SourceArrayHandleType = vtkm::cont::ArrayHandle<ComponentType, SourceStorageTag>;
public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -253,32 +256,32 @@ public:
}
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
if (this->SourceArray.GetNumberOfValues() % NUM_COMPONENTS != 0)
{
throw vtkm::cont::ErrorBadValue(
"ArrayHandleGroupVec's source array does not divide evenly into Vecs.");
}
return PortalConstExecution(this->SourceArray.PrepareForInput(Device()));
return PortalConstExecution(this->SourceArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
if (this->SourceArray.GetNumberOfValues() % NUM_COMPONENTS != 0)
{
throw vtkm::cont::ErrorBadValue(
"ArrayHandleGroupVec's source array does not divide evenly into Vecs.");
}
return PortalExecution(this->SourceArray.PrepareForInPlace(Device()));
return PortalExecution(this->SourceArray.PrepareForInPlace(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(
this->SourceArray.PrepareForOutput(numberOfValues * NUM_COMPONENTS, Device()));
this->SourceArray.PrepareForOutput(numberOfValues * NUM_COMPONENTS, Device(), token));
}
VTKM_CONT
@ -320,7 +323,7 @@ template <typename SourceArrayHandleType, vtkm::IdComponent NUM_COMPONENTS>
class ArrayHandleGroupVec
: public vtkm::cont::ArrayHandle<
vtkm::Vec<typename SourceArrayHandleType::ValueType, NUM_COMPONENTS>,
vtkm::cont::internal::StorageTagGroupVec<SourceArrayHandleType, NUM_COMPONENTS>>
vtkm::cont::StorageTagGroupVec<typename SourceArrayHandleType::StorageTag, NUM_COMPONENTS>>
{
VTKM_IS_ARRAY_HANDLE(SourceArrayHandleType);
@ -330,7 +333,7 @@ public:
(ArrayHandleGroupVec<SourceArrayHandleType, NUM_COMPONENTS>),
(vtkm::cont::ArrayHandle<
vtkm::Vec<typename SourceArrayHandleType::ValueType, NUM_COMPONENTS>,
vtkm::cont::internal::StorageTagGroupVec<SourceArrayHandleType, NUM_COMPONENTS>>));
vtkm::cont::StorageTagGroupVec<typename SourceArrayHandleType::StorageTag, NUM_COMPONENTS>>));
using ComponentType = typename SourceArrayHandleType::ValueType;
@ -378,11 +381,11 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleGroupVec<AH, NUM_COMPS>>
}
};
template <typename AH, vtkm::IdComponent NUM_COMPS>
template <typename T, vtkm::IdComponent NUM_COMPS, typename ST>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::Vec<typename AH::ValueType, NUM_COMPS>,
vtkm::cont::internal::StorageTagGroupVec<AH, NUM_COMPS>>>
: SerializableTypeString<vtkm::cont::ArrayHandleGroupVec<AH, NUM_COMPS>>
vtkm::cont::ArrayHandle<vtkm::Vec<T, NUM_COMPS>, vtkm::cont::StorageTagGroupVec<ST, NUM_COMPS>>>
: SerializableTypeString<
vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<T, ST>, NUM_COMPS>>
{
};
}
@ -413,11 +416,10 @@ public:
}
};
template <typename AH, vtkm::IdComponent NUM_COMPS>
template <typename T, vtkm::IdComponent NUM_COMPS, typename ST>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::Vec<typename AH::ValueType, NUM_COMPS>,
vtkm::cont::internal::StorageTagGroupVec<AH, NUM_COMPS>>>
: Serialization<vtkm::cont::ArrayHandleGroupVec<AH, NUM_COMPS>>
vtkm::cont::ArrayHandle<vtkm::Vec<T, NUM_COMPS>, vtkm::cont::StorageTagGroupVec<ST, NUM_COMPS>>>
: Serialization<vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<T, ST>, NUM_COMPS>>
{
};

@ -11,6 +11,7 @@
#define vtk_m_cont_ArrayHandleGroupVecVariable_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayGetValues.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayPortal.h>
@ -69,22 +70,14 @@ public:
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->OffsetsPortal.GetNumberOfValues(); }
vtkm::Id GetNumberOfValues() const { return this->OffsetsPortal.GetNumberOfValues() - 1; }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const
{
vtkm::Id offsetIndex = this->OffsetsPortal.Get(index);
vtkm::Id nextOffsetIndex;
if (index + 1 < this->GetNumberOfValues())
{
nextOffsetIndex = this->OffsetsPortal.Get(index + 1);
}
else
{
nextOffsetIndex = this->SourcePortal.GetNumberOfValues();
}
vtkm::Id nextOffsetIndex = this->OffsetsPortal.Get(index + 1);
return ValueType(this->SourcePortal,
static_cast<vtkm::IdComponent>(nextOffsetIndex - offsetIndex),
@ -161,30 +154,35 @@ namespace vtkm
namespace cont
{
namespace internal
{
template <typename SourceArrayHandleType, typename OffsetsArrayHandleType>
template <typename SourceStorageTag, typename OffsetsStorageTag>
struct VTKM_ALWAYS_EXPORT StorageTagGroupVecVariable
{
};
template <typename SourceArrayHandleType, typename OffsetsArrayHandleType>
class Storage<
vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SourceArrayHandleType, OffsetsArrayHandleType>>
namespace internal
{
using ComponentType = typename SourceArrayHandleType::ValueType;
template <typename SourcePortal, typename SourceStorageTag, typename OffsetsStorageTag>
class Storage<vtkm::VecFromPortal<SourcePortal>,
vtkm::cont::StorageTagGroupVecVariable<SourceStorageTag, OffsetsStorageTag>>
{
using ComponentType = typename SourcePortal::ValueType;
using SourceArrayHandleType = vtkm::cont::ArrayHandle<ComponentType, SourceStorageTag>;
using OffsetsArrayHandleType = vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>;
VTKM_STATIC_ASSERT_MSG(
(std::is_same<SourcePortal, typename SourceArrayHandleType::WritePortalType>::value),
"Used invalid SourcePortal type with expected SourceStorageTag.");
public:
using ValueType = vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>;
using ValueType = vtkm::VecFromPortal<SourcePortal>;
using PortalType = vtkm::exec::internal::ArrayPortalGroupVecVariable<
typename SourceArrayHandleType::PortalControl,
typename OffsetsArrayHandleType::PortalConstControl>;
typename SourceArrayHandleType::WritePortalType,
typename OffsetsArrayHandleType::ReadPortalType>;
using PortalConstType = vtkm::exec::internal::ArrayPortalGroupVecVariable<
typename SourceArrayHandleType::PortalConstControl,
typename OffsetsArrayHandleType::PortalConstControl>;
typename SourceArrayHandleType::ReadPortalType,
typename OffsetsArrayHandleType::ReadPortalType>;
VTKM_CONT
Storage()
@ -203,22 +201,20 @@ public:
VTKM_CONT
PortalType GetPortal()
{
return PortalType(this->SourceArray.GetPortalControl(),
this->OffsetsArray.GetPortalConstControl());
return PortalType(this->SourceArray.WritePortal(), this->OffsetsArray.ReadPortal());
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
return PortalConstType(this->SourceArray.GetPortalConstControl(),
this->OffsetsArray.GetPortalConstControl());
return PortalConstType(this->SourceArray.ReadPortal(), this->OffsetsArray.ReadPortal());
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const
{
VTKM_ASSERT(this->Valid);
return this->OffsetsArray.GetNumberOfValues();
return this->OffsetsArray.GetNumberOfValues() - 1;
}
VTKM_CONT
@ -231,7 +227,7 @@ public:
void Shrink(vtkm::Id numberOfValues)
{
VTKM_ASSERT(this->Valid);
this->OffsetsArray.Shrink(numberOfValues);
this->OffsetsArray.Shrink(numberOfValues + 1);
}
VTKM_CONT
@ -266,21 +262,25 @@ private:
bool Valid;
};
template <typename SourceArrayHandleType, typename OffsetsArrayHandleType, typename Device>
class ArrayTransfer<
vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SourceArrayHandleType, OffsetsArrayHandleType>,
Device>
template <typename SourcePortal,
typename SourceStorageTag,
typename OffsetsStorageTag,
typename Device>
class ArrayTransfer<vtkm::VecFromPortal<SourcePortal>,
vtkm::cont::StorageTagGroupVecVariable<SourceStorageTag, OffsetsStorageTag>,
Device>
{
public:
using ComponentType = typename SourceArrayHandleType::ValueType;
using ValueType = vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>;
using ComponentType = typename SourcePortal::ValueType;
using ValueType = vtkm::VecFromPortal<SourcePortal>;
private:
using StorageTag =
vtkm::cont::internal::StorageTagGroupVecVariable<SourceArrayHandleType, OffsetsArrayHandleType>;
using StorageTag = vtkm::cont::StorageTagGroupVecVariable<SourceStorageTag, OffsetsStorageTag>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using SourceArrayHandleType = vtkm::cont::ArrayHandle<ComponentType, SourceStorageTag>;
using OffsetsArrayHandleType = vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>;
public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -300,30 +300,30 @@ public:
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const { return this->OffsetsArray.GetNumberOfValues(); }
vtkm::Id GetNumberOfValues() const { return this->OffsetsArray.GetNumberOfValues() - 1; }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->SourceArray.PrepareForInput(Device()),
this->OffsetsArray.PrepareForInput(Device()));
return PortalConstExecution(this->SourceArray.PrepareForInput(Device(), token),
this->OffsetsArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->SourceArray.PrepareForInPlace(Device()),
this->OffsetsArray.PrepareForInput(Device()));
return PortalExecution(this->SourceArray.PrepareForInPlace(Device(), token),
this->OffsetsArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
// Cannot reallocate an ArrayHandleGroupVecVariable
VTKM_ASSERT(numberOfValues == this->OffsetsArray.GetNumberOfValues());
VTKM_ASSERT(numberOfValues == this->OffsetsArray.GetNumberOfValues() - 1);
return PortalExecution(
this->SourceArray.PrepareForOutput(this->SourceArray.GetNumberOfValues(), Device()),
this->OffsetsArray.PrepareForInput(Device()));
this->SourceArray.PrepareForOutput(this->SourceArray.GetNumberOfValues(), Device(), token),
this->OffsetsArray.PrepareForInput(Device(), token));
}
VTKM_CONT
@ -364,7 +364,7 @@ private:
/// value contains values from the last offset to the end of the array.
///
/// For example, if you have an array handle with the 9 values
/// 0,1,2,3,4,5,6,7,8 an offsets array handle with the 3 values 0,4,6 and give
/// 0,1,2,3,4,5,6,7,8 an offsets array handle with the 4 values 0,4,6,9 and give
/// them to an \c ArrayHandleGroupVecVariable, you get an array that looks like
/// it contains three values of Vec-like objects with the data [0,1,2,3],
/// [4,5], and [6,7,8].
@ -386,21 +386,25 @@ private:
template <typename SourceArrayHandleType, typename OffsetsArrayHandleType>
class ArrayHandleGroupVecVariable
: public vtkm::cont::ArrayHandle<
vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SourceArrayHandleType,
OffsetsArrayHandleType>>
vtkm::VecFromPortal<typename SourceArrayHandleType::WritePortalType>,
vtkm::cont::StorageTagGroupVecVariable<typename SourceArrayHandleType::StorageTag,
typename OffsetsArrayHandleType::StorageTag>>
{
VTKM_IS_ARRAY_HANDLE(SourceArrayHandleType);
VTKM_IS_ARRAY_HANDLE(OffsetsArrayHandleType);
VTKM_STATIC_ASSERT_MSG(
(std::is_same<vtkm::Id, typename OffsetsArrayHandleType::ValueType>::value),
"ArrayHandleGroupVecVariable's offsets array must contain vtkm::Id values.");
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleGroupVecVariable,
(ArrayHandleGroupVecVariable<SourceArrayHandleType, OffsetsArrayHandleType>),
(vtkm::cont::ArrayHandle<
vtkm::VecFromPortal<typename SourceArrayHandleType::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SourceArrayHandleType,
OffsetsArrayHandleType>>));
vtkm::VecFromPortal<typename SourceArrayHandleType::WritePortalType>,
vtkm::cont::StorageTagGroupVecVariable<typename SourceArrayHandleType::StorageTag,
typename OffsetsArrayHandleType::StorageTag>>));
using ComponentType = typename SourceArrayHandleType::ValueType;
@ -452,10 +456,12 @@ VTKM_CONT void ConvertNumComponentsToOffsets(
vtkm::Id& sourceArraySize,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
{
using namespace vtkm::cont;
VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
sourceArraySize = vtkm::cont::Algorithm::ScanExclusive(
device, vtkm::cont::make_ArrayHandleCast<vtkm::Id>(numComponentsArray), offsetsArray);
Algorithm::ScanExtended(device, make_ArrayHandleCast<vtkm::Id>(numComponentsArray), offsetsArray);
sourceArraySize = ArrayGetValue(offsetsArray.GetNumberOfValues() - 1, offsetsArray);
}
template <typename NumComponentsArrayType, typename OffsetsStorage>
@ -466,8 +472,8 @@ VTKM_CONT void ConvertNumComponentsToOffsets(
{
VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
vtkm::Id dummy;
vtkm::cont::ConvertNumComponentsToOffsets(numComponentsArray, offsetsArray, dummy, device);
vtkm::cont::Algorithm::ScanExtended(
device, vtkm::cont::make_ArrayHandleCast<vtkm::Id>(numComponentsArray), offsetsArray);
}
template <typename NumComponentsArrayType>
@ -516,11 +522,13 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>>
}
};
template <typename SAH, typename OAH>
template <typename SP, typename SST, typename OST>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::VecFromPortal<typename SAH::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SAH, OAH>>>
: SerializableTypeString<vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>>
vtkm::cont::ArrayHandle<vtkm::VecFromPortal<SP>,
vtkm::cont::StorageTagGroupVecVariable<SST, OST>>>
: SerializableTypeString<
vtkm::cont::ArrayHandleGroupVecVariable<vtkm::cont::ArrayHandle<typename SP::ValueType, SST>,
vtkm::cont::ArrayHandle<vtkm::Id, OST>>>
{
};
}
@ -555,11 +563,12 @@ public:
}
};
template <typename SAH, typename OAH>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::VecFromPortal<typename SAH::PortalControl>,
vtkm::cont::internal::StorageTagGroupVecVariable<SAH, OAH>>>
: Serialization<vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>>
template <typename SP, typename SST, typename OST>
struct Serialization<vtkm::cont::ArrayHandle<vtkm::VecFromPortal<SP>,
vtkm::cont::StorageTagGroupVecVariable<SST, OST>>>
: Serialization<
vtkm::cont::ArrayHandleGroupVecVariable<vtkm::cont::ArrayHandle<typename SP::ValueType, SST>,
vtkm::cont::ArrayHandle<vtkm::Id, OST>>>
{
};
} // diy

@ -32,6 +32,7 @@ struct ArrayHandleImplicitTraits
using ValueType = decltype(FunctorType{}(vtkm::Id{}));
using StorageTag = vtkm::cont::StorageTagImplicit<ArrayPortalImplicit<FunctorType>>;
using Superclass = vtkm::cont::ArrayHandle<ValueType, StorageTag>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
};
/// \brief An array portal that returns the result of a functor
@ -74,12 +75,6 @@ public:
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const { return this->Functor(index); }
using IteratorType =
vtkm::cont::internal::IteratorFromArrayPortal<ArrayPortalImplicit<FunctorType>>;
VTKM_CONT
IteratorType GetIteratorBegin() const { return IteratorType(*this); }
private:
FunctorType Functor;
vtkm::Id NumberOfValues;
@ -108,7 +103,7 @@ public:
VTKM_CONT
ArrayHandleImplicit(FunctorType functor, vtkm::Id length)
: Superclass(typename Superclass::PortalConstControl(functor, length))
: Superclass(typename ArrayTraits::StorageType::PortalType(functor, length))
{
}
};
@ -168,7 +163,7 @@ public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
vtkmdiy::save(bb, obj.GetNumberOfValues());
vtkmdiy::save(bb, obj.GetPortalConstControl().GetFunctor());
vtkmdiy::save(bb, obj.ReadPortal().GetFunctor());
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)

@ -17,7 +17,11 @@ namespace vtkm
namespace cont
{
namespace detail
struct VTKM_ALWAYS_EXPORT StorageTagIndex
{
};
namespace internal
{
struct VTKM_ALWAYS_EXPORT IndexFunctor
@ -26,7 +30,25 @@ struct VTKM_ALWAYS_EXPORT IndexFunctor
vtkm::Id operator()(vtkm::Id index) const { return index; }
};
} // namespace detail
using StorageTagIndexSuperclass =
typename vtkm::cont::ArrayHandleImplicit<IndexFunctor>::StorageTag;
template <>
struct Storage<vtkm::Id, vtkm::cont::StorageTagIndex> : Storage<vtkm::Id, StorageTagIndexSuperclass>
{
using Superclass = Storage<vtkm::Id, StorageTagIndexSuperclass>;
using Superclass::Superclass;
};
template <typename Device>
struct ArrayTransfer<vtkm::Id, vtkm::cont::StorageTagIndex, Device>
: ArrayTransfer<vtkm::Id, StorageTagIndexSuperclass, Device>
{
using Superclass = ArrayTransfer<vtkm::Id, StorageTagIndexSuperclass, Device>;
using Superclass::Superclass;
};
} // namespace internal
/// \brief An implicit array handle containing the its own indices.
///
@ -34,18 +56,27 @@ struct VTKM_ALWAYS_EXPORT IndexFunctor
/// 0, 1, 2, 3,... to a specified size. Every value in the array is the same
/// as the index to that value.
///
class ArrayHandleIndex : public vtkm::cont::ArrayHandleImplicit<detail::IndexFunctor>
class ArrayHandleIndex : public vtkm::cont::ArrayHandle<vtkm::Id, StorageTagIndex>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS_NT(ArrayHandleIndex,
(vtkm::cont::ArrayHandleImplicit<detail::IndexFunctor>));
(vtkm::cont::ArrayHandle<vtkm::Id, StorageTagIndex>));
VTKM_CONT
ArrayHandleIndex(vtkm::Id length)
: Superclass(detail::IndexFunctor(), length)
: Superclass(
typename internal::Storage<vtkm::Id, StorageTagIndex>::PortalType(internal::IndexFunctor{},
length))
{
}
};
/// A convenience function for creating an ArrayHandleIndex. It takes the
/// size of the array and generates an array holding vtkm::Id from [0, size - 1]
VTKM_CONT inline vtkm::cont::ArrayHandleIndex make_ArrayHandleIndex(vtkm::Id length)
{
return vtkm::cont::ArrayHandleIndex(length);
}
}
} // namespace vtkm::cont
@ -59,14 +90,14 @@ namespace cont
{
template <>
struct SerializableTypeString<vtkm::cont::detail::IndexFunctor>
struct SerializableTypeString<vtkm::cont::ArrayHandleIndex>
{
static VTKM_CONT const std::string Get() { return "AH_IndexFunctor"; }
static VTKM_CONT const std::string Get() { return "AH_Index"; }
};
template <>
struct SerializableTypeString<vtkm::cont::ArrayHandleIndex>
: SerializableTypeString<vtkm::cont::ArrayHandleImplicit<vtkm::cont::detail::IndexFunctor>>
struct SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>>
: SerializableTypeString<vtkm::cont::ArrayHandleIndex>
{
};
}
@ -76,19 +107,31 @@ namespace mangled_diy_namespace
{
template <>
struct Serialization<vtkm::cont::detail::IndexFunctor>
struct Serialization<vtkm::cont::ArrayHandleIndex>
{
static VTKM_CONT void save(BinaryBuffer&, const vtkm::cont::detail::IndexFunctor&) {}
private:
using BaseType = vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>;
static VTKM_CONT void load(BinaryBuffer&, vtkm::cont::detail::IndexFunctor&) {}
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
vtkmdiy::save(bb, obj.GetNumberOfValues());
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
{
vtkm::Id length = 0;
vtkmdiy::load(bb, length);
obj = vtkm::cont::ArrayHandleIndex(length);
}
};
template <>
struct Serialization<vtkm::cont::ArrayHandleIndex>
: Serialization<vtkm::cont::ArrayHandleImplicit<vtkm::cont::detail::IndexFunctor>>
struct Serialization<vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>>
: Serialization<vtkm::cont::ArrayHandleIndex>
{
};
} // diy
/// @endcond SERIALIZATION

@ -10,7 +10,6 @@
#ifndef vtk_m_cont_ArrayHandleMultiplexer_h
#define vtk_m_cont_ArrayHandleMultiplexer_h
#include <vtkm/TypeListTag.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/internal/Variant.h>
@ -19,7 +18,6 @@
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/StorageListTag.h>
namespace vtkm
{
@ -182,10 +180,10 @@ private:
using StorageToArrayHandle = vtkm::cont::ArrayHandle<ValueType, S>;
template <typename S>
using StorageToPortalControl = typename StorageToArrayHandle<S>::PortalControl;
using StorageToPortalControl = typename StorageToArrayHandle<S>::WritePortalType;
template <typename S>
using StorageToPortalConstControl = typename StorageToArrayHandle<S>::PortalConstControl;
using StorageToPortalConstControl = typename StorageToArrayHandle<S>::ReadPortalType;
using ArrayHandleVariantType = vtkm::internal::Variant<StorageToArrayHandle<StorageTags>...>;
ArrayHandleVariantType ArrayHandleVariant;
@ -233,7 +231,7 @@ private:
template <typename ArrayHandleType>
VTKM_CONT PortalType operator()(ArrayHandleType&& array) const
{
return PortalType(array.GetPortalControl());
return PortalType(array.WritePortal());
}
};
@ -242,7 +240,7 @@ private:
template <typename ArrayHandleType>
VTKM_CONT PortalConstType operator()(ArrayHandleType&& array) const
{
return PortalConstType(array.GetPortalConstControl());
return PortalConstType(array.ReadPortal());
}
};
@ -356,20 +354,24 @@ public:
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->StoragePointer->GetNumberOfValues(); }
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData),
vtkm::cont::Token& token)
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInputFunctor{});
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInputFunctor{},
token);
}
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData),
vtkm::cont::Token& token)
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInPlaceFunctor{});
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInPlaceFunctor{},
token);
}
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForOutputFunctor{},
numberOfValues);
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(
PrepareForOutputFunctor{}, numberOfValues, token);
}
VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
@ -395,27 +397,30 @@ private:
struct PrepareForInputFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalConstExecution operator()(const ArrayHandleType& array)
VTKM_CONT PortalConstExecution operator()(const ArrayHandleType& array,
vtkm::cont::Token& token)
{
return PortalConstExecution(array.PrepareForInput(Device{}));
return PortalConstExecution(array.PrepareForInput(Device{}, token));
}
};
struct PrepareForInPlaceFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalExecution operator()(ArrayHandleType& array)
VTKM_CONT PortalExecution operator()(ArrayHandleType& array, vtkm::cont::Token& token)
{
return PortalExecution(array.PrepareForInPlace(Device{}));
return PortalExecution(array.PrepareForInPlace(Device{}, token));
}
};
struct PrepareForOutputFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalExecution operator()(ArrayHandleType& array, vtkm::Id numberOfValues)
VTKM_CONT PortalExecution operator()(ArrayHandleType& array,
vtkm::Id numberOfValues,
vtkm::cont::Token& token)
{
return PortalExecution(array.PrepareForOutput(numberOfValues, Device{}));
return PortalExecution(array.PrepareForOutput(numberOfValues, Device{}, token));
}
};
};
@ -534,8 +539,22 @@ public:
/// the list tag must be some type of \c ArrayHandle. The templated type gets aliased to
/// an \c ArrayHandleMultiplexer that can store any of these ArrayHandle types.
///
/// Deprecated. Use `ArrayHandleMultiplexerFromList` instead.
///
template <typename ListTag>
using ArrayHandleMultiplexerFromListTag = vtkm::ListTagApply<ListTag, ArrayHandleMultiplexer>;
using ArrayHandleMultiplexerFromListTag VTKM_DEPRECATED(
1.6,
"vtkm::ListTag is no longer supported. Use vtkm::List instead.") =
vtkm::ListApply<ListTag, ArrayHandleMultiplexer>;
/// \brief Converts a`vtkm::List` to an `ArrayHandleMultiplexer`
///
/// The argument of this template must be a `vtkm::List` and furthermore all the types in
/// the list tag must be some type of \c ArrayHandle. The templated type gets aliased to
/// an \c ArrayHandleMultiplexer that can store any of these ArrayHandle types.
///
template <typename List>
using ArrayHandleMultiplexerFromList = vtkm::ListApply<List, ArrayHandleMultiplexer>;
} // namespace cont

@ -100,30 +100,35 @@ namespace vtkm
namespace cont
{
namespace internal
{
template <typename IndexArrayType, typename ValueArrayType>
template <typename IndexStorageTag, typename ValueStorageTag>
struct VTKM_ALWAYS_EXPORT StorageTagPermutation
{
};
template <typename IndexArrayType, typename ValueArrayType>
class Storage<typename ValueArrayType::ValueType,
StorageTagPermutation<IndexArrayType, ValueArrayType>>
namespace internal
{
VTKM_IS_ARRAY_HANDLE(IndexArrayType);
VTKM_IS_ARRAY_HANDLE(ValueArrayType);
template <typename T, typename IndexStorageTag, typename ValueStorageTag>
class Storage<T, vtkm::cont::StorageTagPermutation<IndexStorageTag, ValueStorageTag>>
{
VTKM_STATIC_ASSERT_MSG(
(vtkm::cont::internal::IsValidArrayHandle<vtkm::Id, IndexStorageTag>::value),
"Invalid index storage tag.");
VTKM_STATIC_ASSERT_MSG((vtkm::cont::internal::IsValidArrayHandle<T, ValueStorageTag>::value),
"Invalid value storage tag.");
public:
using ValueType = typename ValueArrayType::ValueType;
using IndexArrayType = vtkm::cont::ArrayHandle<vtkm::Id, IndexStorageTag>;
using ValueArrayType = vtkm::cont::ArrayHandle<T, ValueStorageTag>;
using ValueType = T;
using PortalType =
vtkm::exec::internal::ArrayPortalPermutation<typename IndexArrayType::PortalConstControl,
typename ValueArrayType::PortalControl>;
vtkm::exec::internal::ArrayPortalPermutation<typename IndexArrayType::ReadPortalType,
typename ValueArrayType::WritePortalType>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalPermutation<typename IndexArrayType::PortalConstControl,
typename ValueArrayType::PortalConstControl>;
vtkm::exec::internal::ArrayPortalPermutation<typename IndexArrayType::ReadPortalType,
typename ValueArrayType::ReadPortalType>;
VTKM_CONT
Storage()
@ -143,16 +148,14 @@ public:
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->IndexArray.GetPortalConstControl(),
this->ValueArray.GetPortalControl());
return PortalType(this->IndexArray.ReadPortal(), this->ValueArray.WritePortal());
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(this->IndexArray.GetPortalConstControl(),
this->ValueArray.GetPortalConstControl());
return PortalConstType(this->IndexArray.ReadPortal(), this->ValueArray.ReadPortal());
}
VTKM_CONT
@ -194,18 +197,19 @@ private:
bool Valid;
};
template <typename IndexArrayType, typename ValueArrayType, typename Device>
class ArrayTransfer<typename ValueArrayType::ValueType,
StorageTagPermutation<IndexArrayType, ValueArrayType>,
Device>
template <typename T, typename IndexStorageTag, typename ValueStorageTag, typename Device>
class ArrayTransfer<T, StorageTagPermutation<IndexStorageTag, ValueStorageTag>, Device>
{
public:
using ValueType = typename ValueArrayType::ValueType;
using ValueType = T;
private:
using StorageTag = StorageTagPermutation<IndexArrayType, ValueArrayType>;
using StorageTag = StorageTagPermutation<IndexStorageTag, ValueStorageTag>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using IndexArrayType = typename StorageType::IndexArrayType;
using ValueArrayType = typename StorageType::ValueArrayType;
public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -228,21 +232,21 @@ public:
vtkm::Id GetNumberOfValues() const { return this->IndexArray.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->IndexArray.PrepareForInput(Device()),
this->ValueArray.PrepareForInput(Device()));
return PortalConstExecution(this->IndexArray.PrepareForInput(Device(), token),
this->ValueArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->IndexArray.PrepareForInput(Device()),
this->ValueArray.PrepareForInPlace(Device()));
return PortalExecution(this->IndexArray.PrepareForInput(Device(), token),
this->ValueArray.PrepareForInPlace(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
if (numberOfValues != this->GetNumberOfValues())
{
@ -264,8 +268,8 @@ public:
}
return PortalExecution(
this->IndexArray.PrepareForInput(Device()),
this->ValueArray.PrepareForOutput(this->ValueArray.GetNumberOfValues(), Device()));
this->IndexArray.PrepareForInput(Device(), token),
this->ValueArray.PrepareForOutput(this->ValueArray.GetNumberOfValues(), Device(), token));
}
VTKM_CONT
@ -323,7 +327,8 @@ template <typename IndexArrayHandleType, typename ValueArrayHandleType>
class ArrayHandlePermutation
: public vtkm::cont::ArrayHandle<
typename ValueArrayHandleType::ValueType,
internal::StorageTagPermutation<IndexArrayHandleType, ValueArrayHandleType>>
vtkm::cont::StorageTagPermutation<typename IndexArrayHandleType::StorageTag,
typename ValueArrayHandleType::StorageTag>>
{
// If the following line gives a compile error, then the ArrayHandleType
// template argument is not a valid ArrayHandle type.
@ -336,7 +341,8 @@ public:
(ArrayHandlePermutation<IndexArrayHandleType, ValueArrayHandleType>),
(vtkm::cont::ArrayHandle<
typename ValueArrayHandleType::ValueType,
internal::StorageTagPermutation<IndexArrayHandleType, ValueArrayHandleType>>));
vtkm::cont::StorageTagPermutation<typename IndexArrayHandleType::StorageTag,
typename ValueArrayHandleType::StorageTag>>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
@ -382,11 +388,12 @@ struct SerializableTypeString<vtkm::cont::ArrayHandlePermutation<IdxAH, ValAH>>
}
};
template <typename IdxAH, typename ValAH>
template <typename T, typename IdxST, typename ValST>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<typename ValAH::ValueType,
vtkm::cont::internal::StorageTagPermutation<IdxAH, ValAH>>>
: SerializableTypeString<vtkm::cont::ArrayHandlePermutation<IdxAH, ValAH>>
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagPermutation<IdxST, ValST>>>
: SerializableTypeString<
vtkm::cont::ArrayHandlePermutation<vtkm::cont::ArrayHandle<vtkm::Id, IdxST>,
vtkm::cont::ArrayHandle<T, ValST>>>
{
};
}
@ -422,11 +429,10 @@ public:
}
};
template <typename IdxAH, typename ValAH>
struct Serialization<
vtkm::cont::ArrayHandle<typename ValAH::ValueType,
vtkm::cont::internal::StorageTagPermutation<IdxAH, ValAH>>>
: Serialization<vtkm::cont::ArrayHandlePermutation<IdxAH, ValAH>>
template <typename T, typename IdxST, typename ValST>
struct Serialization<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagPermutation<IdxST, ValST>>>
: Serialization<vtkm::cont::ArrayHandlePermutation<vtkm::cont::ArrayHandle<vtkm::Id, IdxST>,
vtkm::cont::ArrayHandle<T, ValST>>>
{
};

@ -15,6 +15,8 @@
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/Deprecated.h>
namespace vtkm
{
namespace cont
@ -70,21 +72,59 @@ private:
};
}
template <typename ArrayHandleType>
class StorageTagReverse
template <typename StorageTag>
class VTKM_ALWAYS_EXPORT StorageTagReverse
{
};
namespace internal
{
template <typename ArrayHandleType>
class Storage<typename ArrayHandleType::ValueType, StorageTagReverse<ArrayHandleType>>
namespace detail
{
template <typename T, typename ArrayOrStorage, bool IsArrayType>
struct ReverseTypeArgImpl;
template <typename T, typename Storage>
struct ReverseTypeArgImpl<T, Storage, false>
{
using StorageTag = Storage;
using ArrayHandle = vtkm::cont::ArrayHandle<T, StorageTag>;
};
template <typename T, typename Array>
struct ReverseTypeArgImpl<T, Array, true>
{
VTKM_STATIC_ASSERT_MSG((std::is_same<T, typename Array::ValueType>::value),
"Used array with wrong type in ArrayHandleReverse.");
using StorageTag VTKM_DEPRECATED(
1.6,
"Use storage tag instead of array handle in StorageTagReverse.") = typename Array::StorageTag;
using ArrayHandle VTKM_DEPRECATED(
1.6,
"Use storage tag instead of array handle in StorageTagReverse.") =
vtkm::cont::ArrayHandle<T, typename Array::StorageTag>;
};
template <typename T, typename ArrayOrStorage>
struct ReverseTypeArg
: ReverseTypeArgImpl<T,
ArrayOrStorage,
vtkm::cont::internal::ArrayHandleCheck<ArrayOrStorage>::type::value>
{
};
} // namespace detail
template <typename T, typename ST>
class Storage<T, StorageTagReverse<ST>>
{
public:
using ValueType = typename ArrayHandleType::ValueType;
using PortalType = ArrayPortalReverse<typename ArrayHandleType::PortalControl>;
using PortalConstType = ArrayPortalReverse<typename ArrayHandleType::PortalConstControl>;
using ValueType = T;
using ArrayHandleType = typename detail::ReverseTypeArg<T, ST>::ArrayHandle;
using PortalType = ArrayPortalReverse<typename ArrayHandleType::WritePortalType>;
using PortalConstType = ArrayPortalReverse<typename ArrayHandleType::ReadPortalType>;
VTKM_CONT
Storage()
@ -100,13 +140,10 @@ public:
VTKM_CONT
PortalConstType GetPortalConst() const
{
return PortalConstType(this->Array.GetPortalConstControl());
}
PortalConstType GetPortalConst() const { return PortalConstType(this->Array.ReadPortal()); }
VTKM_CONT
PortalType GetPortal() { return PortalType(this->Array.GetPortalControl()); }
PortalType GetPortal() { return PortalType(this->Array.WritePortal()); }
VTKM_CONT
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
@ -132,17 +169,16 @@ private:
ArrayHandleType Array;
}; // class storage
template <typename ArrayHandleType, typename Device>
class ArrayTransfer<typename ArrayHandleType::ValueType, StorageTagReverse<ArrayHandleType>, Device>
template <typename T, typename ST, typename Device>
class ArrayTransfer<T, StorageTagReverse<ST>, Device>
{
public:
using ValueType = typename ArrayHandleType::ValueType;
private:
using StorageTag = StorageTagReverse<ArrayHandleType>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using StorageTag = StorageTagReverse<ST>;
using StorageType = vtkm::cont::internal::Storage<T, StorageTag>;
using ArrayHandleType = typename detail::ReverseTypeArg<T, ST>::ArrayHandle;
public:
using ValueType = T;
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -161,21 +197,21 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->Array.PrepareForInput(Device()));
return PortalConstExecution(this->Array.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForInPlace(Device()));
return PortalExecution(this->Array.PrepareForInPlace(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()));
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device(), token));
}
VTKM_CONT
@ -203,18 +239,17 @@ private:
/// order (i.e. from end to beginning).
///
template <typename ArrayHandleType>
class ArrayHandleReverse : public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagReverse<ArrayHandleType>>
class ArrayHandleReverse
: public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagReverse<typename ArrayHandleType::StorageTag>>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleReverse,
(ArrayHandleReverse<ArrayHandleType>),
(vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagReverse<ArrayHandleType>>));
protected:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleReverse,
(ArrayHandleReverse<ArrayHandleType>),
(vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagReverse<typename ArrayHandleType::StorageTag>>));
public:
ArrayHandleReverse(const ArrayHandleType& handle)
@ -252,10 +287,9 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleReverse<AH>>
}
};
template <typename AH>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<typename AH::ValueType, vtkm::cont::StorageTagReverse<AH>>>
: SerializableTypeString<vtkm::cont::ArrayHandleReverse<AH>>
template <typename T, typename ST>
struct SerializableTypeString<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagReverse<ST>>>
: SerializableTypeString<vtkm::cont::ArrayHandleReverse<vtkm::cont::ArrayHandle<T, ST>>>
{
};
}
@ -285,10 +319,9 @@ public:
}
};
template <typename AH>
struct Serialization<
vtkm::cont::ArrayHandle<typename AH::ValueType, vtkm::cont::StorageTagReverse<AH>>>
: Serialization<vtkm::cont::ArrayHandleReverse<AH>>
template <typename T, typename ST>
struct Serialization<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagReverse<ST>>>
: Serialization<vtkm::cont::ArrayHandleReverse<vtkm::cont::ArrayHandle<T, ST>>>
{
};

@ -182,11 +182,11 @@ struct ArrayHandleSOATraits
using IsTrueVec = std::integral_constant<bool, (NUM_COMPONENTS > 1)>;
using PortalControl = typename detail::SOAPortalChooser<ValueType,
typename BaseArrayType::PortalControl,
typename BaseArrayType::WritePortalType,
IsTrueVec>::Type;
using PortalConstControl =
typename detail::SOAPortalChooser<ValueType,
typename BaseArrayType::PortalConstControl,
typename BaseArrayType::ReadPortalType,
IsTrueVec>::Type;
template <typename Device>
@ -282,7 +282,7 @@ public:
VTKM_ASSERT(this->IsValid());
return detail::MakeSOAPortal<PortalType>(
this->Arrays, this->GetNumberOfValues(), [](BaseArrayType& array) {
return array.GetPortalControl();
return array.WritePortal();
});
}
@ -291,7 +291,7 @@ public:
VTKM_ASSERT(this->IsValid());
return detail::MakeSOAPortal<PortalConstType>(
this->Arrays, this->GetNumberOfValues(), [](const BaseArrayType& array) {
return array.GetPortalConstControl();
return array.ReadPortal();
});
}
@ -349,27 +349,29 @@ public:
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); }
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) const
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData),
vtkm::cont::Token& token) const
{
return detail::MakeSOAPortal<PortalConstExecution>(
this->Storage->GetArrays(), this->GetNumberOfValues(), [](const BaseArrayType& array) {
return array.PrepareForInput(Device{});
this->Storage->GetArrays(), this->GetNumberOfValues(), [&token](const BaseArrayType& array) {
return array.PrepareForInput(Device{}, token);
});
}
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData)) const
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData),
vtkm::cont::Token& token) const
{
return detail::MakeSOAPortal<PortalExecution>(
this->Storage->GetArrays(), this->GetNumberOfValues(), [](BaseArrayType& array) {
return array.PrepareForInPlace(Device{});
this->Storage->GetArrays(), this->GetNumberOfValues(), [&token](BaseArrayType& array) {
return array.PrepareForInPlace(Device{}, token);
});
}
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numValues) const
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numValues, vtkm::cont::Token& token) const
{
return detail::MakeSOAPortal<PortalExecution>(
this->Storage->GetArrays(), numValues, [numValues](BaseArrayType& array) {
return array.PrepareForOutput(numValues, Device{});
this->Storage->GetArrays(), numValues, [numValues, &token](BaseArrayType& array) {
return array.PrepareForOutput(numValues, Device{}, token);
});
}

@ -29,7 +29,8 @@ public:
using PortalType = P;
using ValueType = typename PortalType::ValueType;
VTKM_CONT
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming()
: InputPortal()
, BlockIndex(0)
@ -38,7 +39,8 @@ public:
{
}
VTKM_CONT
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming(const PortalType& inputPortal,
vtkm::Id blockIndex,
vtkm::Id blockSize,
@ -50,8 +52,9 @@ public:
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename OtherP>
VTKM_CONT ArrayPortalStreaming(const ArrayPortalStreaming<OtherP>& src)
VTKM_EXEC_CONT ArrayPortalStreaming(const ArrayPortalStreaming<OtherP>& src)
: InputPortal(src.GetPortal())
, BlockIndex(src.GetBlockIndex())
, BlockSize(src.GetBlockSize())
@ -59,10 +62,56 @@ public:
{
}
VTKM_CONT
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming(const ArrayPortalStreaming& src)
: InputPortal(src.InputPortal)
, BlockIndex(src.BlockIndex)
, BlockSize(src.BlockSize)
, CurBlockSize(src.CurBlockSize)
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming(const ArrayPortalStreaming&& rhs)
: InputPortal(std::move(rhs.InputPortal))
, BlockIndex(std::move(rhs.BlockIndex))
, BlockSize(std::move(rhs.BlockSize))
, CurBlockSize(std::move(rhs.CurBlockSize))
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
~ArrayPortalStreaming() {}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming& operator=(const ArrayPortalStreaming& src)
{
this->InputPortal = src.InputPortal;
this->BlockIndex = src.BlockIndex;
this->BlockSize = src.BlockSize;
this->CurBlockSize = src.CurBlockSize;
return *this;
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalStreaming& operator=(const ArrayPortalStreaming&& rhs)
{
this->InputPortal = std::move(rhs.InputPortal);
this->BlockIndex = std::move(rhs.BlockIndex);
this->BlockSize = std::move(rhs.BlockSize);
this->CurBlockSize = std::move(rhs.CurBlockSize);
return *this;
}
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->CurBlockSize; }
VTKM_CONT
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const
{
return this->InputPortal.Get(this->BlockIndex * this->BlockSize + index);
@ -70,30 +119,30 @@ public:
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_CONT void Set(vtkm::Id index, const ValueType& value) const
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->InputPortal.Set(this->BlockIndex * this->BlockSize + index, value);
}
VTKM_CONT
VTKM_EXEC_CONT
const PortalType& GetPortal() const { return this->InputPortal; }
VTKM_CONT
VTKM_EXEC_CONT
void SetBlockSize(vtkm::Id blockSize) { this->BlockSize = blockSize; }
VTKM_CONT
VTKM_EXEC_CONT
void SetBlockIndex(vtkm::Id blockIndex) { this->BlockIndex = blockIndex; }
VTKM_CONT
VTKM_EXEC_CONT
void SetCurBlockSize(vtkm::Id curBlockSize) { this->CurBlockSize = curBlockSize; }
VTKM_CONT
VTKM_EXEC_CONT
vtkm::Id GetBlockSize() { return this->BlockSize; }
VTKM_CONT
VTKM_EXEC_CONT
vtkm::Id GetBlockIndex() { return this->BlockIndex; }
VTKM_CONT
VTKM_EXEC_CONT
vtkm::Id GetCurBlockSize() { return this->CurBlockSize; }
private:
@ -119,10 +168,13 @@ class Storage<typename ArrayHandleInputType::ValueType, StorageTagStreaming<Arra
public:
using ValueType = typename ArrayHandleInputType::ValueType;
using PortalType =
vtkm::cont::internal::ArrayPortalStreaming<typename ArrayHandleInputType::PortalControl>;
using PortalType = vtkm::cont::internal::ArrayPortalStreaming<
typename vtkm::cont::internal::Storage<typename ArrayHandleInputType::ValueType,
typename ArrayHandleInputType::StorageTag>::PortalType>;
using PortalConstType =
vtkm::cont::internal::ArrayPortalStreaming<typename ArrayHandleInputType::PortalConstControl>;
vtkm::cont::internal::ArrayPortalStreaming<typename vtkm::cont::internal::Storage<
typename ArrayHandleInputType::ValueType,
typename ArrayHandleInputType::StorageTag>::PortalConstType>;
VTKM_CONT
Storage()
@ -147,15 +199,14 @@ public:
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->InputArray.GetPortalControl(), BlockSize, BlockIndex, CurBlockSize);
return PortalType(this->InputArray.WritePortal(), BlockSize, BlockIndex, CurBlockSize);
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(
this->InputArray.GetPortalConstControl(), BlockSize, BlockIndex, CurBlockSize);
return PortalConstType(this->InputArray.ReadPortal(), BlockSize, BlockIndex, CurBlockSize);
}
VTKM_CONT
@ -238,17 +289,19 @@ public:
const vtkm::Id curBlockSize)
: Superclass(StorageType(inputArray, blockIndex, blockSize, curBlockSize))
{
this->GetPortalConstControl().SetBlockIndex(blockIndex);
this->GetPortalConstControl().SetBlockSize(blockSize);
this->GetPortalConstControl().SetCurBlockSize(curBlockSize);
this->ReadPortal().SetBlockIndex(blockIndex);
this->ReadPortal().SetBlockSize(blockSize);
this->ReadPortal().SetCurBlockSize(curBlockSize);
}
VTKM_CONT
void AllocateFullArray(vtkm::Id numberOfValues)
{
this->ReleaseResourcesExecutionInternal();
this->Internals->ControlArray.AllocateFullArray(numberOfValues);
this->Internals->ControlArrayValid = true;
auto lock = this->GetLock();
this->ReleaseResourcesExecutionInternal(lock);
this->Internals->GetControlArray(lock)->AllocateFullArray(numberOfValues);
this->Internals->SetControlArrayValid(lock, true);
}
};
}

@ -144,6 +144,9 @@ public:
{
}
ArrayPortalSwizzle& operator=(const ArrayPortalSwizzle& src) = default;
ArrayPortalSwizzle& operator=(ArrayPortalSwizzle&& src) = default;
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); }
@ -192,9 +195,9 @@ class Storage<typename ResizeVectorType<typename ArrayHandleType::ValueType, Out
public:
using PortalType =
ArrayPortalSwizzle<typename ArrayHandleType::PortalControl, ArrayHandleType, OutSize>;
ArrayPortalSwizzle<typename ArrayHandleType::WritePortalType, ArrayHandleType, OutSize>;
using PortalConstType =
ArrayPortalSwizzle<typename ArrayHandleType::PortalConstControl, ArrayHandleType, OutSize>;
ArrayPortalSwizzle<typename ArrayHandleType::ReadPortalType, ArrayHandleType, OutSize>;
using MapType = typename Traits::MapType;
using ValueType = typename Traits::OutValueType;
@ -217,14 +220,14 @@ public:
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(this->Array.GetPortalConstControl(), this->Map);
return PortalConstType(this->Array.ReadPortal(), this->Map);
}
VTKM_CONT
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->Array.GetPortalControl(), this->Map);
return PortalType(this->Array.WritePortal(), this->Map);
}
VTKM_CONT
@ -306,21 +309,22 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->Array.PrepareForInput(DeviceTag()), this->Map);
return PortalConstExecution(this->Array.PrepareForInput(DeviceTag(), token), this->Map);
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForInPlace(DeviceTag()), this->Map);
return PortalExecution(this->Array.PrepareForInPlace(DeviceTag(), token), this->Map);
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, DeviceTag()), this->Map);
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, DeviceTag(), token),
this->Map);
}
VTKM_CONT

@ -189,7 +189,7 @@ struct TransformFunctorManagerImpl<ProvidedFunctorType, std::false_type>
ProvidedFunctorType PrepareForControl() const { return this->Functor; }
template <typename Device>
VTKM_CONT ProvidedFunctorType PrepareForExecution(Device) const
VTKM_CONT ProvidedFunctorType PrepareForExecution(Device, vtkm::cont::Token&) const
{
return this->Functor;
}
@ -202,7 +202,8 @@ struct TransformFunctorManagerImpl<ProvidedFunctorType, std::true_type>
ProvidedFunctorType Functor;
// using FunctorType = decltype(std::declval<ProvidedFunctorType>().PrepareForControl());
using FunctorType = decltype(Functor.PrepareForControl());
// using FunctorType = decltype(Functor.PrepareForControl());
using FunctorType = vtkm::cont::internal::ControlObjectType<ProvidedFunctorType>;
TransformFunctorManagerImpl() = default;
@ -213,16 +214,17 @@ struct TransformFunctorManagerImpl<ProvidedFunctorType, std::true_type>
}
VTKM_CONT
auto PrepareForControl() const -> decltype(this->Functor.PrepareForControl())
auto PrepareForControl() const
-> decltype(vtkm::cont::internal::CallPrepareForControl(this->Functor))
{
return this->Functor.PrepareForControl();
return vtkm::cont::internal::CallPrepareForControl(this->Functor);
}
template <typename Device>
VTKM_CONT auto PrepareForExecution(Device device) const
-> decltype(this->Functor.PrepareForExecution(device))
VTKM_CONT auto PrepareForExecution(Device device, vtkm::cont::Token& token) const
-> decltype(vtkm::cont::internal::CallPrepareForExecution(this->Functor, device, token))
{
return this->Functor.PrepareForExecution(device);
return vtkm::cont::internal::CallPrepareForExecution(this->Functor, device, token);
}
};
@ -271,7 +273,7 @@ public:
using PortalConstType =
vtkm::exec::internal::ArrayPortalTransform<ValueType,
typename ArrayHandleType::PortalConstControl,
typename ArrayHandleType::ReadPortalType,
typename FunctorManager::FunctorType>;
// Note that this array is read only, so you really should only be getting the const
@ -305,7 +307,7 @@ public:
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.PrepareForControl());
return PortalConstType(this->Array.ReadPortal(), this->Functor.PrepareForControl());
}
VTKM_CONT
@ -365,12 +367,12 @@ public:
using PortalType =
vtkm::exec::internal::ArrayPortalTransform<ValueType,
typename ArrayHandleType::PortalControl,
typename ArrayHandleType::WritePortalType,
typename FunctorManager::FunctorType,
typename InverseFunctorManager::FunctorType>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalTransform<ValueType,
typename ArrayHandleType::PortalConstControl,
typename ArrayHandleType::ReadPortalType,
typename FunctorManager::FunctorType,
typename InverseFunctorManager::FunctorType>;
@ -382,8 +384,8 @@ public:
VTKM_CONT
Storage(const ArrayHandleType& array,
const FunctorType& functor,
const InverseFunctorType& inverseFunctor)
const FunctorType& functor = FunctorType(),
const InverseFunctorType& inverseFunctor = InverseFunctorType())
: Array(array)
, Functor(functor)
, InverseFunctor(inverseFunctor)
@ -396,7 +398,7 @@ public:
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalType(this->Array.GetPortalControl(),
return PortalType(this->Array.WritePortal(),
this->Functor.PrepareForControl(),
this->InverseFunctor.PrepareForControl());
}
@ -406,7 +408,7 @@ public:
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalConstType(this->Array.GetPortalConstControl(),
return PortalConstType(this->Array.ReadPortal(),
this->Functor.PrepareForControl(),
this->InverseFunctor.PrepareForControl());
}
@ -470,8 +472,12 @@ public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
//meant to be an invalid writeable execution portal
using PortalExecution = typename StorageType::PortalType;
// You can get the "writable" version of the portal, but you will not actually be
// able to write to it.
using PortalExecution = vtkm::exec::internal::ArrayPortalTransform<
ValueType,
typename ArrayHandleType::template ExecutionTypes<Device>::Portal,
typename FunctorManager::FunctorType>;
using PortalConstExecution = vtkm::exec::internal::ArrayPortalTransform<
ValueType,
typename ArrayHandleType::template ExecutionTypes<Device>::PortalConst,
@ -488,21 +494,21 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->Array.PrepareForInput(Device()),
this->Functor.PrepareForExecution(Device()));
return PortalConstExecution(this->Array.PrepareForInput(Device{}, token),
this->Functor.PrepareForExecution(Device{}, token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("ArrayHandleTransform read only. "
"Cannot be used for in-place operations.");
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues))
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues), vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("ArrayHandleTransform read only. Cannot be used as output.");
}
@ -573,27 +579,27 @@ public:
vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->Array.PrepareForInput(Device()),
this->Functor.PrepareForExecution(Device()),
this->InverseFunctor.PrepareForExecution(Device()));
return PortalConstExecution(this->Array.PrepareForInput(Device{}, token),
this->Functor.PrepareForExecution(Device{}, token),
this->InverseFunctor.PrepareForExecution(Device{}, token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForInPlace(Device()),
this->Functor.PrepareForExecution(Device()),
this->InverseFunctor.PrepareForExecution(Device()));
return PortalExecution(this->Array.PrepareForInPlace(Device{}, token),
this->Functor.PrepareForExecution(Device{}, token),
this->InverseFunctor.PrepareForExecution(Device{}, token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()),
this->Functor.PrepareForExecution(Device()),
this->InverseFunctor.PrepareForExecution(Device()));
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device{}, token),
this->Functor.PrepareForExecution(Device{}, token),
this->InverseFunctor.PrepareForExecution(Device{}, token));
}
VTKM_CONT
@ -703,6 +709,13 @@ public:
: Superclass(StorageType(handle, functor, inverseFunctor))
{
}
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
~ArrayHandleTransform() {}
};
template <typename HandleType, typename FunctorType, typename InverseFunctorType>

@ -19,22 +19,48 @@ namespace vtkm
namespace cont
{
struct VTKM_ALWAYS_EXPORT StorageTagUniformPoints
{
};
namespace internal
{
using StorageTagUniformPointsSuperclass =
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>;
template <>
struct Storage<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>
: Storage<vtkm::Vec3f, StorageTagUniformPointsSuperclass>
{
using Superclass = Storage<vtkm::Vec3f, StorageTagUniformPointsSuperclass>;
using Superclass::Superclass;
};
template <typename Device>
struct ArrayTransfer<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints, Device>
: ArrayTransfer<vtkm::Vec3f, StorageTagUniformPointsSuperclass, Device>
{
using Superclass = ArrayTransfer<vtkm::Vec3f, StorageTagUniformPointsSuperclass, Device>;
using Superclass::Superclass;
};
} // namespace internal
/// ArrayHandleUniformPointCoordinates is a specialization of ArrayHandle. It
/// contains the information necessary to compute the point coordinates in a
/// uniform orthogonal grid (extent, origin, and spacing) and implicitly
/// computes these coordinates in its array portal.
///
class VTKM_ALWAYS_EXPORT ArrayHandleUniformPointCoordinates
: public vtkm::cont::ArrayHandle<
vtkm::Vec3f,
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>>
: public vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS_NT(
ArrayHandleUniformPointCoordinates,
(vtkm::cont::ArrayHandle<
vtkm::Vec3f,
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>>));
(vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
@ -48,6 +74,13 @@ public:
vtkm::internal::ArrayPortalUniformPointCoordinates(dimensions, origin, spacing)))
{
}
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
~ArrayHandleUniformPointCoordinates() {}
};
}
} // namespace vtkm::cont
@ -67,9 +100,8 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleUniformPointCoordinates>
};
template <>
struct SerializableTypeString<vtkm::cont::ArrayHandle<
vtkm::Vec3f,
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>>>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>>
: SerializableTypeString<vtkm::cont::ArrayHandleUniformPointCoordinates>
{
};
@ -89,7 +121,7 @@ private:
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
auto portal = obj.GetPortalConstControl();
auto portal = obj.ReadPortal();
vtkmdiy::save(bb, portal.GetDimensions());
vtkmdiy::save(bb, portal.GetOrigin());
vtkmdiy::save(bb, portal.GetSpacing());
@ -109,9 +141,7 @@ public:
};
template <>
struct Serialization<vtkm::cont::ArrayHandle<
vtkm::Vec3f,
vtkm::cont::StorageTagImplicit<vtkm::internal::ArrayPortalUniformPointCoordinates>>>
struct Serialization<vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>>
: Serialization<vtkm::cont::ArrayHandleUniformPointCoordinates>
{
};

@ -11,6 +11,7 @@
#define vtk_m_cont_ArrayHandleView_h
#include <vtkm/Assert.h>
#include <vtkm/Deprecated.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayPortal.h>
@ -81,22 +82,60 @@ private:
} // namespace internal
template <typename ArrayHandleType>
struct StorageTagView
template <typename StorageTag>
struct VTKM_ALWAYS_EXPORT StorageTagView
{
};
namespace internal
{
template <typename ArrayHandleType>
class Storage<typename ArrayHandleType::ValueType, StorageTagView<ArrayHandleType>>
namespace detail
{
public:
using ValueType = typename ArrayHandleType::ValueType;
using PortalType = ArrayPortalView<typename ArrayHandleType::PortalControl>;
using PortalConstType = ArrayPortalView<typename ArrayHandleType::PortalConstControl>;
template <typename T, typename ArrayOrStorage, bool IsArrayType>
struct ViewTypeArgImpl;
template <typename T, typename Storage>
struct ViewTypeArgImpl<T, Storage, false>
{
using StorageTag = Storage;
using ArrayHandle = vtkm::cont::ArrayHandle<T, StorageTag>;
};
template <typename T, typename Array>
struct ViewTypeArgImpl<T, Array, true>
{
VTKM_STATIC_ASSERT_MSG((std::is_same<T, typename Array::ValueType>::value),
"Used array with wrong type in ArrayHandleView.");
using StorageTag VTKM_DEPRECATED(1.6,
"Use storage tag instead of array handle in StorageTagView.") =
typename Array::StorageTag;
using ArrayHandle VTKM_DEPRECATED(1.6,
"Use storage tag instead of array handle in StorageTagView.") =
vtkm::cont::ArrayHandle<T, typename Array::StorageTag>;
};
template <typename T, typename ArrayOrStorage>
struct ViewTypeArg
: ViewTypeArgImpl<T,
ArrayOrStorage,
vtkm::cont::internal::ArrayHandleCheck<ArrayOrStorage>::type::value>
{
};
} // detail
template <typename T, typename ST>
class Storage<T, StorageTagView<ST>>
{
using ArrayHandleType = typename detail::ViewTypeArg<T, ST>::ArrayHandle;
public:
using ValueType = T;
using PortalType = ArrayPortalView<typename ArrayHandleType::WritePortalType>;
using PortalConstType = ArrayPortalView<typename ArrayHandleType::ReadPortalType>;
VTKM_CONT
Storage()
@ -119,14 +158,14 @@ public:
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
return PortalType(this->Array.GetPortalControl(), this->StartIndex, this->NumValues);
return PortalType(this->Array.WritePortal(), this->StartIndex, this->NumValues);
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
return PortalConstType(this->Array.GetPortalConstControl(), this->StartIndex, this->NumValues);
return PortalConstType(this->Array.ReadPortal(), this->StartIndex, this->NumValues);
}
VTKM_CONT
@ -174,17 +213,15 @@ private:
bool Valid;
};
template <typename ArrayHandleType, typename Device>
class ArrayTransfer<typename ArrayHandleType::ValueType, StorageTagView<ArrayHandleType>, Device>
template <typename T, typename ST, typename Device>
class ArrayTransfer<T, StorageTagView<ST>, Device>
{
public:
using ValueType = typename ArrayHandleType::ValueType;
private:
using StorageTag = StorageTagView<ArrayHandleType>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using StorageType = vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagView<ST>>;
using ArrayHandleType = typename detail::ViewTypeArg<T, ST>::ArrayHandle;
public:
using ValueType = T;
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -205,21 +242,21 @@ public:
vtkm::Id GetNumberOfValues() const { return this->NumValues; }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(
this->Array.PrepareForInput(Device()), this->StartIndex, this->NumValues);
this->Array.PrepareForInput(Device(), token), this->StartIndex, this->NumValues);
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(
this->Array.PrepareForInPlace(Device()), this->StartIndex, this->NumValues);
this->Array.PrepareForInPlace(Device(), token), this->StartIndex, this->NumValues);
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
if (numberOfValues != this->GetNumberOfValues())
{
@ -240,9 +277,10 @@ public:
"output of ArrayHandlePermutation.");
}
return PortalExecution(this->Array.PrepareForOutput(this->Array.GetNumberOfValues(), Device()),
this->StartIndex,
this->NumValues);
return PortalExecution(
this->Array.PrepareForOutput(this->Array.GetNumberOfValues(), Device(), token),
this->StartIndex,
this->NumValues);
}
VTKM_CONT
@ -266,16 +304,18 @@ private:
} // namespace internal
template <typename ArrayHandleType>
class ArrayHandleView : public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagView<ArrayHandleType>>
class ArrayHandleView
: public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagView<typename ArrayHandleType::StorageTag>>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleView,
(ArrayHandleView<ArrayHandleType>),
(vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagView<ArrayHandleType>>));
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleView,
(ArrayHandleView<ArrayHandleType>),
(vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagView<typename ArrayHandleType::StorageTag>>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;

@ -39,7 +39,6 @@ public:
using T = typename ValueType::FirstType;
using U = typename ValueType::SecondType;
using IteratorType = ValueType_;
using PortalTypeFirst = PortalTypeFirst_;
using PortalTypeSecond = PortalTypeSecond_;
@ -106,14 +105,14 @@ namespace vtkm
namespace cont
{
namespace internal
{
template <typename FirstHandleType, typename SecondHandleType>
template <typename ST1, typename ST2>
struct VTKM_ALWAYS_EXPORT StorageTagZip
{
};
namespace internal
{
/// This helper struct defines the value type for a zip container containing
/// the given two array handles.
///
@ -127,31 +126,31 @@ struct ArrayHandleZipTraits
/// The appropriately templated tag.
///
using Tag = StorageTagZip<FirstHandleType, SecondHandleType>;
using Tag =
StorageTagZip<typename FirstHandleType::StorageTag, typename SecondHandleType::StorageTag>;
/// The superclass for ArrayHandleZip.
///
using Superclass = vtkm::cont::ArrayHandle<ValueType, Tag>;
};
template <typename FirstHandleType, typename SecondHandleType>
class Storage<vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>,
StorageTagZip<FirstHandleType, SecondHandleType>>
template <typename T1, typename T2, typename ST1, typename ST2>
class Storage<vtkm::Pair<T1, T2>, vtkm::cont::StorageTagZip<ST1, ST2>>
{
VTKM_IS_ARRAY_HANDLE(FirstHandleType);
VTKM_IS_ARRAY_HANDLE(SecondHandleType);
using FirstHandleType = vtkm::cont::ArrayHandle<T1, ST1>;
using SecondHandleType = vtkm::cont::ArrayHandle<T2, ST2>;
public:
using ValueType =
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>;
using ValueType = vtkm::Pair<T1, T2>;
using PortalType = vtkm::exec::internal::ArrayPortalZip<ValueType,
typename FirstHandleType::PortalControl,
typename SecondHandleType::PortalControl>;
using PortalType =
vtkm::exec::internal::ArrayPortalZip<ValueType,
typename FirstHandleType::WritePortalType,
typename SecondHandleType::WritePortalType>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalZip<ValueType,
typename FirstHandleType::PortalConstControl,
typename SecondHandleType::PortalConstControl>;
typename FirstHandleType::ReadPortalType,
typename SecondHandleType::ReadPortalType>;
VTKM_CONT
Storage()
@ -170,14 +169,13 @@ public:
VTKM_CONT
PortalType GetPortal()
{
return PortalType(this->FirstArray.GetPortalControl(), this->SecondArray.GetPortalControl());
return PortalType(this->FirstArray.WritePortal(), this->SecondArray.WritePortal());
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
return PortalConstType(this->FirstArray.GetPortalConstControl(),
this->SecondArray.GetPortalConstControl());
return PortalConstType(this->FirstArray.ReadPortal(), this->SecondArray.ReadPortal());
}
VTKM_CONT
@ -219,21 +217,18 @@ private:
SecondHandleType SecondArray;
};
template <typename FirstHandleType, typename SecondHandleType, typename Device>
class ArrayTransfer<
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>,
StorageTagZip<FirstHandleType, SecondHandleType>,
Device>
template <typename T1, typename T2, typename ST1, typename ST2, typename Device>
class ArrayTransfer<vtkm::Pair<T1, T2>, vtkm::cont::StorageTagZip<ST1, ST2>, Device>
{
public:
using ValueType =
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>;
using StorageTag = vtkm::cont::StorageTagZip<ST1, ST2>;
using StorageType = vtkm::cont::internal::Storage<vtkm::Pair<T1, T2>, StorageTag>;
private:
using StorageTag = StorageTagZip<FirstHandleType, SecondHandleType>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using FirstHandleType = vtkm::cont::ArrayHandle<T1, ST1>;
using SecondHandleType = vtkm::cont::ArrayHandle<T2, ST2>;
public:
using ValueType = vtkm::Pair<T1, T2>;
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
@ -262,24 +257,24 @@ public:
}
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalConstExecution(this->FirstArray.PrepareForInput(Device()),
this->SecondArray.PrepareForInput(Device()));
return PortalConstExecution(this->FirstArray.PrepareForInput(Device(), token),
this->SecondArray.PrepareForInput(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token& token)
{
return PortalExecution(this->FirstArray.PrepareForInPlace(Device()),
this->SecondArray.PrepareForInPlace(Device()));
return PortalExecution(this->FirstArray.PrepareForInPlace(Device(), token),
this->SecondArray.PrepareForInPlace(Device(), token));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
return PortalExecution(this->FirstArray.PrepareForOutput(numberOfValues, Device()),
this->SecondArray.PrepareForOutput(numberOfValues, Device()));
return PortalExecution(this->FirstArray.PrepareForOutput(numberOfValues, Device(), token),
this->SecondArray.PrepareForOutput(numberOfValues, Device(), token));
}
VTKM_CONT
@ -375,11 +370,11 @@ struct SerializableTypeString<vtkm::cont::ArrayHandleZip<AH1, AH2>>
}
};
template <typename AH1, typename AH2>
template <typename T1, typename T2, typename ST1, typename ST2>
struct SerializableTypeString<
vtkm::cont::ArrayHandle<vtkm::Pair<typename AH1::ValueType, typename AH2::ValueType>,
vtkm::cont::internal::StorageTagZip<AH1, AH2>>>
: SerializableTypeString<vtkm::cont::ArrayHandleZip<AH1, AH2>>
vtkm::cont::ArrayHandle<vtkm::Pair<T1, T2>, vtkm::cont::StorageTagZip<ST1, ST2>>>
: SerializableTypeString<vtkm::cont::ArrayHandleZip<vtkm::cont::ArrayHandle<T1, ST1>,
vtkm::cont::ArrayHandle<T2, ST2>>>
{
};
}
@ -415,11 +410,11 @@ public:
}
};
template <typename AH1, typename AH2>
template <typename T1, typename T2, typename ST1, typename ST2>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::Pair<typename AH1::ValueType, typename AH2::ValueType>,
vtkm::cont::internal::StorageTagZip<AH1, AH2>>>
: Serialization<vtkm::cont::ArrayHandleZip<AH1, AH2>>
vtkm::cont::ArrayHandle<vtkm::Pair<T1, T2>, vtkm::cont::StorageTagZip<ST1, ST2>>>
: Serialization<vtkm::cont::ArrayHandleZip<vtkm::cont::ArrayHandle<T1, ST1>,
vtkm::cont::ArrayHandle<T2, ST2>>>
{
};

@ -51,6 +51,13 @@ namespace cont
/// (e.g., ArrayHandleCast may be casting a read-only OR read-write array), the
/// Set method may be conditionally removed using SFINAE.
///
/// The ArrayPortalToIterators utilities wrap ArrayPortals in STL-style
/// iterators. If an ArrayPortal implementation wishes to provide a custom
/// iterator type, it may define an IteratorType type alias along with the
/// methods `IteratorType GetIteratorBegin()` and
/// `IteratorType GetIteratorEnd()`. These are not required members, but if
/// present, will allow additional optimizations for certain portals.
///
template <typename T>
class ArrayPortal
{

@ -13,11 +13,42 @@
#include <vtkm/cont/ArrayPortal.h>
#include <vtkm/cont/internal/IteratorFromArrayPortal.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
namespace vtkmstd
{
/// Implementation of std::void_t (C++17):
/// Allows for specialization of class templates based on members of template
/// parameters.
#if defined(VTKM_GCC) && (__GNUC__ < 5)
// Due to a defect in the wording (CWG 1558) unused parameters in alias templates
// were not guaranteed to ensure SFINAE, and therefore would consider everything
// to match the 'true' side. For VTK-m the only known compiler that implemented
// this defect is GCC < 5.
template <class... T>
struct void_pack
{
using type = void;
};
template <class... T>
using void_t = typename void_pack<T...>::type;
#else
template <typename...>
using void_t = void;
#endif
} // end namespace vtkmstd
namespace vtkm
{
namespace cont
{
template <typename PortalType,
typename CustomIterators = vtkm::internal::PortalSupportsIterators<PortalType>>
class ArrayPortalToIterators;
/// \brief Convert an \c ArrayPortal to STL iterators.
///
/// \c ArrayPortalToIterators is a class that holds an \c ArrayPortal and
@ -26,13 +57,12 @@ namespace cont
/// STL iterators such as STL algorithms or Thrust operations.
///
/// The default template implementation constructs iterators that provide
/// values through the \c ArrayPortal itself. This class can be specialized to
/// provide iterators that more directly access the data. For example, \c
/// ArrayPortalFromIterator has a specialization to return the original
/// iterators.
/// values through the \c ArrayPortal itself. However, if the \c ArrayPortal
/// contains its own iterators (by defining \c GetIteratorBegin and
/// \c GetIteratorEnd), then those iterators are used.
///
template <typename PortalType>
class ArrayPortalToIterators
class ArrayPortalToIterators<PortalType, std::false_type>
{
public:
/// \c ArrayPortaltoIterators should be constructed with an instance of
@ -40,11 +70,44 @@ public:
///
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators(const PortalType& portal)
explicit ArrayPortalToIterators(const PortalType& portal)
: Portal(portal)
{
}
// These are the same as the default implementation, but explicitly created to prevent warnings
// from the CUDA compiler where it tries to compile for the device when the underlying portal
// only works for the host.
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators(const ArrayPortalToIterators& src)
: Portal(src.Portal)
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators(ArrayPortalToIterators&& rhs)
: Portal(std::move(rhs.Portal))
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
~ArrayPortalToIterators() {}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators& operator=(const ArrayPortalToIterators& src)
{
this->Portal = src.Portal;
return *this;
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators& operator=(ArrayPortalToIterators&& rhs)
{
this->Portal = std::move(rhs.Portal);
return *this;
}
/// The type of the iterator.
///
using IteratorType = vtkm::cont::internal::IteratorFromArrayPortal<PortalType>;
@ -65,6 +128,71 @@ private:
PortalType Portal;
};
// Specialize for custom iterator types:
template <typename PortalType>
class ArrayPortalToIterators<PortalType, std::true_type>
{
public:
using IteratorType = decltype(std::declval<PortalType>().GetIteratorBegin());
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
explicit ArrayPortalToIterators(const PortalType& portal)
: Begin(portal.GetIteratorBegin())
, End(portal.GetIteratorEnd())
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
IteratorType GetBegin() const { return this->Begin; }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
IteratorType GetEnd() const { return this->End; }
// These are the same as the default implementation, but explicitly created to prevent warnings
// from the CUDA compiler where it tries to compile for the device when the underlying portal
// only works for the host.
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators(const ArrayPortalToIterators& src)
: Begin(src.Begin)
, End(src.End)
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators(ArrayPortalToIterators&& rhs)
: Begin(std::move(rhs.Begin))
, End(std::move(rhs.End))
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
~ArrayPortalToIterators() {}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators& operator=(const ArrayPortalToIterators& src)
{
this->Begin = src.Begin;
this->End = src.End;
return *this;
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalToIterators& operator=(ArrayPortalToIterators&& rhs)
{
this->Begin = std::move(rhs.Begin);
this->End = std::move(rhs.End);
return *this;
}
private:
IteratorType Begin;
IteratorType End;
};
/// Convenience function for converting an ArrayPortal to a begin iterator.
///
VTKM_SUPPRESS_EXEC_WARNINGS

@ -77,7 +77,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::DeviceAdapterId)
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.GetPortalConstControl();
vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.ReadPortal();
// In this portal we know that the min value is the first entry and the
// max value is the last entry.
@ -86,7 +86,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
rangeArray.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range>::PortalControl outPortal = rangeArray.GetPortalControl();
vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));

@ -117,11 +117,10 @@ VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComput
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Implementation of cartesian products
template <typename T, typename ArrayType1, typename ArrayType2, typename ArrayType3>
template <typename T, typename ST1, typename ST2, typename ST3>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<
T,
vtkm::cont::internal::StorageTagCartesianProduct<ArrayType1, ArrayType2, ArrayType3>>& input,
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
@ -130,20 +129,20 @@ VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::Range componentRange;
ArrayType1 firstArray = input.GetStorage().GetFirstArray();
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetStorage().GetFirstArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(0, componentRange);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(0, componentRange);
ArrayType2 secondArray = input.GetStorage().GetSecondArray();
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetStorage().GetSecondArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(1, componentRange);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(1, componentRange);
ArrayType3 thirdArray = input.GetStorage().GetThirdArray();
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetStorage().GetThirdArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(2, componentRange);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(2, componentRange);
return result;
}

@ -56,7 +56,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
if (input.GetNumberOfValues() < 1)
{
auto portal = range.GetPortalControl();
auto portal = range.WritePortal();
for (vtkm::IdComponent i = 0; i < VecTraits::NUM_COMPONENTS; ++i)
{
portal.Set(i, vtkm::Range());
@ -79,7 +79,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
}
else
{
auto portal = range.GetPortalControl();
auto portal = range.WritePortal();
for (vtkm::IdComponent i = 0; i < VecTraits::NUM_COMPONENTS; ++i)
{
portal.Set(i,

@ -49,6 +49,11 @@ AssignerPartitionedDataSet::AssignerPartitionedDataSet(vtkm::Id num_partitions)
this->set_nblocks(static_cast<int>(this->IScanPartitionCounts.back()));
}
VTKM_CONT
AssignerPartitionedDataSet::~AssignerPartitionedDataSet()
{
}
VTKM_CONT
void AssignerPartitionedDataSet::local_gids(int my_rank, std::vector<int>& gids) const
{

@ -58,6 +58,9 @@ public:
VTKM_CONT
AssignerPartitionedDataSet(vtkm::Id num_partitions);
VTKM_CONT
virtual ~AssignerPartitionedDataSet();
///@{
/// vtkmdiy::Assigner API implementation.
VTKM_CONT

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_AtomicArray_h
#define vtk_m_cont_AtomicArray_h
#include <vtkm/List.h>
#include <vtkm/ListTag.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/cont/ArrayHandle.h>
@ -24,8 +25,12 @@ namespace cont
/// \brief A type list containing types that can be used with an AtomicArray.
///
struct AtomicArrayTypeListTag
: vtkm::ListTagBase<vtkm::UInt32, vtkm::Int32, vtkm::UInt64, vtkm::Int64>
using AtomicArrayTypeList = vtkm::List<vtkm::UInt32, vtkm::Int32, vtkm::UInt64, vtkm::Int64>;
struct VTKM_DEPRECATED(1.6,
"AtomicArrayTypeListTag replaced by AtomicArrayTypeList. Note that the "
"new AtomicArrayTypeList cannot be subclassed.") AtomicArrayTypeListTag
: vtkm::internal::ListAsListTag<AtomicArrayTypeList>
{
};
@ -48,7 +53,7 @@ struct AtomicArrayTypeListTag
template <typename T>
class AtomicArray : public vtkm::cont::ExecutionObjectBase
{
static constexpr bool ValueTypeIsValid = vtkm::ListContains<AtomicArrayTypeListTag, T>::value;
static constexpr bool ValueTypeIsValid = vtkm::ListHas<AtomicArrayTypeList, T>::value;
VTKM_STATIC_ASSERT_MSG(ValueTypeIsValid, "AtomicArray used with unsupported ValueType.");
@ -67,9 +72,19 @@ public:
}
template <typename Device>
VTKM_CONT vtkm::exec::AtomicArrayExecutionObject<T, Device> PrepareForExecution(Device) const
VTKM_CONT vtkm::exec::AtomicArrayExecutionObject<T, Device> PrepareForExecution(
Device,
vtkm::cont::Token& token) const
{
return vtkm::exec::AtomicArrayExecutionObject<T, Device>(this->Handle);
return vtkm::exec::AtomicArrayExecutionObject<T, Device>(this->Handle, token);
}
template <typename Device>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForExecution now requires a vtkm::cont::Token object.")
vtkm::exec::AtomicArrayExecutionObject<T, Device> PrepareForExecution(Device device) const
{
vtkm::cont::Token token;
return this->PrepareForExecution(device, token);
}
private:

@ -17,7 +17,8 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/ListTag.h>
#include <vtkm/Deprecated.h>
#include <vtkm/List.h>
#include <vtkm/Types.h>
#include <cassert>
@ -61,16 +62,16 @@ struct BitFieldTraits
/// Require an unsigned integral type that is <= BlockSize bytes, and is
/// is supported by the specified AtomicInterface.
template <typename WordType, typename AtomicInterface>
using IsValidWordTypeAtomic = std::integral_constant<
bool,
/* is unsigned */
std::is_unsigned<WordType>::value &&
/* doesn't exceed blocksize */
sizeof(WordType) <= static_cast<size_t>(BlockSize) &&
/* BlockSize is a multiple of WordType */
static_cast<size_t>(BlockSize) % sizeof(WordType) == 0 &&
/* Supported by atomic interface */
vtkm::ListContains<typename AtomicInterface::WordTypes, WordType>::value>;
using IsValidWordTypeAtomic =
std::integral_constant<bool,
/* is unsigned */
std::is_unsigned<WordType>::value &&
/* doesn't exceed blocksize */
sizeof(WordType) <= static_cast<size_t>(BlockSize) &&
/* BlockSize is a multiple of WordType */
static_cast<size_t>(BlockSize) % sizeof(WordType) == 0 &&
/* Supported by atomic interface */
vtkm::ListHas<typename AtomicInterface::WordTypes, WordType>::value>;
};
/// Identifies a bit in a BitField by Word and BitOffset. Note that these
@ -500,10 +501,17 @@ public:
using ArrayHandleType = ArrayHandle<WordTypeDefault, StorageTagBasic>;
/// The BitPortal used in the control environment.
using PortalControl = detail::BitPortal<vtkm::cont::internal::AtomicInterfaceControl>;
using WritePortalType = vtkm::cont::internal::ArrayPortalToken<
detail::BitPortal<vtkm::cont::internal::AtomicInterfaceControl>>;
/// A read-only BitPortal used in the control environment.
using PortalConstControl = detail::BitPortalConst<vtkm::cont::internal::AtomicInterfaceControl>;
using ReadPortalType = vtkm::cont::internal::ArrayPortalToken<
detail::BitPortalConst<vtkm::cont::internal::AtomicInterfaceControl>>;
using PortalControl VTKM_DEPRECATED(1.6, "Use BitField::WritePortalType instead.") =
detail::BitPortal<vtkm::cont::internal::AtomicInterfaceControl>;
using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayBitField::ReadPortalType instead.") =
detail::BitPortalConst<vtkm::cont::internal::AtomicInterfaceControl>;
template <typename Device>
struct ExecutionTypes
@ -624,20 +632,46 @@ public:
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const { return this->Internals->Data.GetDeviceAdapterId(); }
/// Get a portal to the data that is usable from the control environment.
VTKM_CONT
PortalControl GetPortalControl()
/// \brief Get a portal to the data that is usable from the control environment.
///
/// As long as this portal is in scope, no one else will be able to read or write the BitField.
VTKM_CONT WritePortalType WritePortal() const
{
return PortalControl{ this->Internals->Data.GetPortalControl(), this->Internals->NumberOfBits };
auto dataPortal = this->Internals->Data.WritePortal();
return WritePortalType{ dataPortal.GetToken(), dataPortal, this->Internals->NumberOfBits };
}
/// \brief Get a read-only portal to the data that is usable from the control environment.
///
/// As long as this portal is in scope, no one else will be able to write in the BitField.
VTKM_CONT ReadPortalType ReadPortal() const
{
auto dataPortal = this->Internals->Data.ReadPortal();
return ReadPortalType{ dataPortal.GetToken(), dataPortal, this->Internals->NumberOfBits };
}
VTKM_CONT
VTKM_DEPRECATED(1.6,
"Use BitField::WritePortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
detail::BitPortal<vtkm::cont::internal::AtomicInterfaceControl> GetPortalControl()
{
return detail::BitPortal<vtkm::cont::internal::AtomicInterfaceControl>{
this->Internals->Data.WritePortal(), this->Internals->NumberOfBits
};
}
/// Get a read-only portal to the data that is usable from the control
/// environment.
VTKM_CONT
PortalConstControl GetPortalConstControl() const
VTKM_DEPRECATED(1.6,
"Use BitField::ReadPortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
detail::BitPortalConst<vtkm::cont::internal::AtomicInterfaceControl> GetPortalConstControl() const
{
return PortalConstControl{ this->Internals->Data.GetPortalConstControl(),
this->Internals->NumberOfBits };
return detail::BitPortalConst<vtkm::cont::internal::AtomicInterfaceControl>{
this->Internals->Data.ReadPortal(), this->Internals->NumberOfBits
};
}
/// Prepares this BitField to be used as an input to an operation in the
@ -647,13 +681,23 @@ public:
/// execution environment.
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(
DeviceAdapterTag device) const
DeviceAdapterTag device,
vtkm::cont::Token& token) const
{
using PortalType = typename ExecutionTypes<DeviceAdapterTag>::PortalConst;
return PortalType{ this->Internals->Data.PrepareForInput(device),
return PortalType{ this->Internals->Data.PrepareForInput(device, token),
this->Internals->NumberOfBits };
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::PortalConst
PrepareForInput(DeviceAdapterTag device) const
{
vtkm::cont::Token token;
return this->PrepareForInput(device, token);
}
/// Prepares (allocates) this BitField to be used as an output from an
/// operation in the execution environment. The internal state of this class
/// is set to have valid data in the execution BitField with the assumption
@ -661,9 +705,8 @@ public:
/// object are called). Returns a portal that can be used in code running in
/// the execution environment.
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForOutput(
vtkm::Id numBits,
DeviceAdapterTag device) const
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numBits, DeviceAdapterTag device, vtkm::cont::Token& token) const
{
using PortalType = typename ExecutionTypes<DeviceAdapterTag>::Portal;
const vtkm::Id numWords = this->BitsToAllocatedStorageWords(numBits);
@ -675,11 +718,20 @@ public:
static_cast<vtkm::UInt64>(static_cast<size_t>(numWords) * sizeof(WordTypeDefault)))
.c_str());
auto portal = this->Internals->Data.PrepareForOutput(numWords, device);
auto portal = this->Internals->Data.PrepareForOutput(numWords, device, token);
this->Internals->NumberOfBits = numBits;
return PortalType{ portal, numBits };
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numBits, DeviceAdapterTag device) const
{
vtkm::cont::Token token;
return this->PrepareForOutput(numBits, device, token);
}
/// Prepares this BitField to be used in an in-place operation (both as input
/// and output) in the execution environment. If necessary, copies data to
/// the execution environment. Can throw an exception if this BitField does
@ -687,13 +739,23 @@ public:
/// running in the execution environment.
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(
DeviceAdapterTag device) const
DeviceAdapterTag device,
vtkm::cont::Token& token) const
{
using PortalType = typename ExecutionTypes<DeviceAdapterTag>::Portal;
return PortalType{ this->Internals->Data.PrepareForInPlace(device),
return PortalType{ this->Internals->Data.PrepareForInPlace(device, token),
this->Internals->NumberOfBits };
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForInPlace(DeviceAdapterTag device) const
{
vtkm::cont::Token token;
return this->PrepareForInPlace(device, token);
}
private:
/// Returns the number of words, padded out to respect BlockSize.
VTKM_CONT

@ -29,12 +29,12 @@ vtkm::Bounds MergeBoundsGlobal(const vtkm::Bounds& local)
{
vtkm::cont::ArrayHandle<vtkm::Range> ranges;
ranges.Allocate(3);
ranges.GetPortalControl().Set(0, local.X);
ranges.GetPortalControl().Set(1, local.Y);
ranges.GetPortalControl().Set(2, local.Z);
ranges.WritePortal().Set(0, local.X);
ranges.WritePortal().Set(1, local.Y);
ranges.WritePortal().Set(2, local.Z);
ranges = vtkm::cont::detail::MergeRangesGlobal(ranges);
auto portal = ranges.GetPortalConstControl();
auto portal = ranges.ReadPortal();
return vtkm::Bounds(portal.Get(0), portal.Get(1), portal.Get(2));
}
}

@ -59,6 +59,7 @@ set(headers
CellSet.h
CellSetExplicit.h
CellSetExtrude.h
CellSetList.h
CellSetListTag.h
CellSetPermutation.h
CellSetSingleType.h
@ -73,6 +74,7 @@ set(headers
DataSetFieldAdd.h
DeviceAdapter.h
DeviceAdapterAlgorithm.h
DeviceAdapterList.h
DeviceAdapterListTag.h
DeviceAdapterTag.h
DynamicCellSet.h
@ -104,9 +106,11 @@ set(headers
StorageBasic.h
StorageExtrude.h
StorageImplicit.h
StorageList.h
StorageListTag.h
StorageVirtual.h
Timer.h
Token.h
TryExecute.h
SerializableTypeString.h
VariantArrayHandle.h
@ -145,6 +149,7 @@ set(sources
Logging.cxx
RuntimeDeviceTracker.cxx
StorageBasic.cxx
Token.cxx
TryExecute.cxx
)
@ -211,6 +216,7 @@ if(TARGET vtkm::openmp)
endif()
target_link_libraries(vtkm_cont PUBLIC vtkm_compiler_flags ${backends})
target_link_libraries(vtkm_cont PUBLIC Threads::Threads)
target_link_libraries(vtkm_cont PUBLIC vtkm_taotuple vtkm_optionparser vtkm_diy vtkm_lcl)
if(TARGET vtkm_loguru)
target_link_libraries(vtkm_cont PRIVATE vtkm_loguru)

@ -56,7 +56,16 @@ public:
}
VTKM_CONT virtual const vtkm::exec::CellLocator* PrepareForExecution(
vtkm::cont::DeviceAdapterId device) const = 0;
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const = 0;
VTKM_CONT
VTKM_DEPRECATED(1.6, "PrepareForExecution now requires a vtkm::cont::Token object.")
const vtkm::exec::CellLocator* PrepareForExecution(vtkm::cont::DeviceAdapterId device) const
{
vtkm::cont::Token token;
return this->PrepareForExecution(device, token);
}
protected:
void SetModified() { this->Modified = true; }

@ -266,13 +266,13 @@ void CellLocatorBoundingIntervalHierarchy::Build()
IdArrayHandle discardKeys;
IdArrayHandle segmentSizes;
segmentSizes.Allocate(1);
segmentSizes.GetPortalControl().Set(0, numCells);
segmentSizes.WritePortal().Set(0, numCells);
this->ProcessedCellIds.Allocate(numCells);
vtkm::Id cellIdsOffset = 0;
IdArrayHandle parentIndices;
parentIndices.Allocate(1);
parentIndices.GetPortalControl().Set(0, -1);
parentIndices.WritePortal().Set(0, -1);
while (!done)
{
@ -453,6 +453,7 @@ struct CellLocatorBIHPrepareForExecutionFunctor
bool operator()(
DeviceAdapter,
const CellSetType& cellset,
vtkm::cont::Token& token,
vtkm::cont::VirtualObjectHandle<vtkm::exec::CellLocator>& bihExec,
const vtkm::cont::ArrayHandle<vtkm::exec::CellLocatorBoundingIntervalHierarchyNode>& nodes,
const vtkm::cont::ArrayHandle<vtkm::Id>& processedCellIds,
@ -461,7 +462,7 @@ struct CellLocatorBIHPrepareForExecutionFunctor
using ExecutionType =
vtkm::exec::CellLocatorBoundingIntervalHierarchyExec<DeviceAdapter, CellSetType>;
ExecutionType* execObject =
new ExecutionType(nodes, processedCellIds, cellset, coords, DeviceAdapter());
new ExecutionType(nodes, processedCellIds, cellset, coords, DeviceAdapter(), token);
bihExec.Reset(execObject);
return true;
}
@ -470,11 +471,17 @@ struct CellLocatorBIHPrepareForExecutionFunctor
struct BIHCellSetCaster
{
template <typename CellSet, typename... Args>
void operator()(CellSet&& cellset, vtkm::cont::DeviceAdapterId device, Args&&... args) const
void operator()(CellSet&& cellset,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token,
Args&&... args) const
{
//We need to go though CastAndCall first
const bool success = vtkm::cont::TryExecuteOnDevice(
device, CellLocatorBIHPrepareForExecutionFunctor(), cellset, std::forward<Args>(args)...);
const bool success = vtkm::cont::TryExecuteOnDevice(device,
CellLocatorBIHPrepareForExecutionFunctor(),
cellset,
token,
std::forward<Args>(args)...);
if (!success)
{
throwFailedRuntimeDeviceTransfer("BoundingIntervalHierarchy", device);
@ -485,15 +492,17 @@ struct BIHCellSetCaster
const vtkm::exec::CellLocator* CellLocatorBoundingIntervalHierarchy::PrepareForExecution(
vtkm::cont::DeviceAdapterId device) const
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
this->GetCellSet().CastAndCall(BIHCellSetCaster{},
device,
token,
this->ExecutionObjectHandle,
this->Nodes,
this->ProcessedCellIds,
this->GetCoordinates().GetData());
return this->ExecutionObjectHandle.PrepareForExecution(device);
return this->ExecutionObjectHandle.PrepareForExecution(device, token);
;
}

@ -62,8 +62,8 @@ public:
vtkm::Id GetMaxLeafSize() { return this->MaxLeafSize; }
VTKM_CONT
const vtkm::exec::CellLocator* PrepareForExecution(
vtkm::cont::DeviceAdapterId device) const override;
const vtkm::exec::CellLocator* PrepareForExecution(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const override;
protected:
VTKM_CONT

Some files were not shown because too many files have changed in this diff Show More