Merge branch 'master' of https://gitlab.kitware.com/vtk/vtk-m into 2DLocators

This commit is contained in:
ayenpure 2019-07-30 09:20:42 -06:00
commit cb01e982c4
102 changed files with 7718 additions and 583 deletions

@ -77,40 +77,58 @@ endif()
set(vec_levels none native)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
#for now we presume gcc > 4.6
list(APPEND vec_levels avx)
#for now we presume gcc >= 4.8
list(APPEND vec_levels avx avx2)
#common flags for the avx instructions for the gcc compiler
#common flags for the avx and avx2 instructions for the gcc compiler
set(native_flags -march=native)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
#GCC PowerPC font end doesn't support the march flag
set(native_flags -mcpu=native -mtune=native)
endif()
set(avx_flags -mavx)
set(avx2_flags ${avx_flags} -mf16c -mavx2 -mfma -mlzcnt -mbmi -mbmi2)
if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.7 OR
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7)
#if GNU is less than 4.9 you get avx, avx2
list(APPEND vec_levels avx2)
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
#if GNU is less than 5.1 you get avx, avx2, and some avx512
list(APPEND vec_levels avx2 avx512-knl)
set(knl_flags ${avx2_flags} -mavx512f -mavx512pf -mavx512er -mavx512cd)
else()
#if GNU is 5.1+ you get avx, avx2, and more avx512
list(APPEND vec_levels avx2 avx512-skx avx512-knl)
set(knl_flags ${avx2_flags} -mavx512f -mavx512pf -mavx512er -mavx512cd)
set(skylake_flags ${avx2_flags} -mavx512f -mavx512dq -mavx512cd -mavx512bw -mavx512vl)
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
#if GNU is less than 5.1 you get avx, avx2, and some avx512
list(APPEND vec_levels avx512-knl)
set(knl_flags ${avx2_flags} -mavx512f -mavx512pf -mavx512er -mavx512cd)
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
#if GNU is 5.1+ to 8.0 we explicit set the flags as they
#only have the concept of knl architecture and not skylake
list(APPEND vec_levels avx512-skx avx512-knl)
set(knl_flags ${avx2_flags} -mavx512f -mavx512pf -mavx512er -mavx512cd)
set(skylake_flags ${avx2_flags} -mavx512f -mavx512dq -mavx512cd -mavx512bw -mavx512vl)
else()
#if GNU is 8+ has architecture names
list(APPEND vec_levels avx512-skx avx512-knl)
set(knl_flags -march=knl)
set(skylake_flags -march=skylake-avx512)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
list(APPEND vec_levels avx avx2 avx512-skx avx512-knl)
set(native_flags -march=native)
set(avx_flags -mavx)
set(avx2_flags ${avx_flags} -mf16c -mavx2 -mfma -mlzcnt -mbmi -mbmi2)
set(knl_flags ${avx2_flags} -avx512f -avx512cd -avx512dq -avx512bw -avx512vl)
set(skylake_flags ${avx2_flags} -avx512f -avx512cd -avx512er -avx512pf)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
set(knl_flags ${avx2_flags} -avx512f -avx512cd -avx512dq -avx512bw -avx512vl)
set(skylake_flags ${avx2_flags} -avx512f -avx512cd -avx512er -avx512pf)
else()
# Clang 4+ introduced skylake-avx512 and knl platforms
set(knl_flags -march=knl)
set(skylake_flags -march=skylake-avx512)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
#While Clang support AVX512, no version of AppleClang has that support yet
list(APPEND vec_levels avx avx2)
set(native_flags -march=native)
set(avx_flags -mavx)
set(avx2_flags ${avx_flags} -mf16c -mavx2 -mfma -mlzcnt -mbmi -mbmi2)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 9.0)
# Manually verified that skylake-avx512 exists in XCode 9.1. Could exist
# in older versions that we dont have access to.
list(APPEND vec_levels avx512-skx)
set(skylake_flags -march=skylake-avx512)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PGI")
#I can't find documentation to explicitly state the level of vectorization
#support I want from the PGI compiler
@ -132,8 +150,8 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
list(APPEND vec_levels avx avx2)
else()
list(APPEND vec_levels avx avx2 avx512-skx avx512-knl)
set(knl_flags ${knl_flags} -xMIC-AVX512)
set(skylake_flags ${skylake_flags} -xCORE-AVX512)
set(knl_flags -xMIC-AVX512)
set(skylake_flags -xCORE-AVX512)
endif()
endif()

@ -98,8 +98,11 @@ elseif(VTKM_COMPILER_IS_ICC)
target_compile_options(vtkm_developer_flags INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-wd1478 -wd13379>)
elseif(VTKM_COMPILER_IS_GNU OR VTKM_COMPILER_IS_CLANG)
set(cxx_flags -Wall -Wcast-align -Wchar-subscripts -Wextra -Wpointer-arith -Wformat -Wformat-security -Wshadow -Wunused-parameter -fno-common)
set(cuda_flags -Xcompiler=-Wall,-Wno-unknown-pragmas,-Wno-unused-local-typedefs,-Wno-unused-local-typedefs,-Wno-unused-function,-Wcast-align,-Wchar-subscripts,-Wpointer-arith,-Wformat,-Wformat-security,-Wshadow,-Wunused-parameter,-fno-common)
set(cxx_flags -Wall -Wcast-align -Wchar-subscripts -Wextra -Wpointer-arith -Wformat -Wformat-security -Wshadow -Wunused -fno-common)
set(cuda_flags -Xcompiler=-Wall,-Wno-unknown-pragmas,-Wno-unused-local-typedefs,-Wno-unused-local-typedefs,-Wno-unused-function,-Wcast-align,-Wchar-subscripts,-Wpointer-arith,-Wformat,-Wformat-security,-Wshadow,-Wunused,-fno-common)
#Only add float-conversion warnings for gcc as the integer warnigns in GCC
#include the implicit casting of all types smaller than int to ints.
if (VTKM_COMPILER_IS_GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.99)
list(APPEND cxx_flags -Wfloat-conversion)
set(cuda_flags "${cuda_flags},-Wfloat-conversion")
@ -108,6 +111,15 @@ elseif(VTKM_COMPILER_IS_GNU OR VTKM_COMPILER_IS_CLANG)
set(cuda_flags "${cuda_flags},-Wconversion")
endif()
#Add in the -Wodr warning for GCC versions 5.2+
if (VTKM_COMPILER_IS_GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.1)
list(APPEND cxx_flags -Wodr)
set(cuda_flags "${cuda_flags},-Wodr")
elseif (VTKM_COMPILER_IS_CLANG)
list(APPEND cxx_flags -Wodr)
set(cuda_flags "${cuda_flags},-Wodr")
endif()
#GCC 5, 6 don't properly handle strict-overflow suppression through pragma's.
#Instead of suppressing around the location of the strict-overflow you
#have to suppress around the entry point, or in vtk-m case the worklet
@ -118,6 +130,7 @@ elseif(VTKM_COMPILER_IS_GNU OR VTKM_COMPILER_IS_CLANG)
(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.99) )
list(APPEND cxx_flags -Wno-strict-overflow)
endif()
target_compile_options(vtkm_developer_flags INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${cxx_flags}>)
if(TARGET vtkm::cuda)
target_compile_options(vtkm_developer_flags INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:${cuda_flags}>)

@ -96,8 +96,8 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${VTKm_CMAKE_MODULE_PATH})
if(VTKm_ENABLE_CUDA)
if (CMAKE_VERSION VERSION_LESS "3.9")
message(FATAL_ERROR "VTK-m with CUDA requires CMake 3.9+")
if (CMAKE_VERSION VERSION_LESS 3.13)
message(FATAL_ERROR "VTK-m with CUDA requires CMake 3.13+")
endif()
endif()

@ -107,7 +107,7 @@ if(VTKm_ENABLE_OPENMP AND NOT TARGET vtkm::openmp)
endif()
if(VTKm_ENABLE_CUDA)
cmake_minimum_required(VERSION 3.9...3.14 FATAL_ERROR)
cmake_minimum_required(VERSION 3.13...3.14 FATAL_ERROR)
enable_language(CUDA)
if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA" AND
@ -115,12 +115,6 @@ if(VTKm_ENABLE_CUDA)
message(FATAL_ERROR "VTK-m CUDA support requires version 9.2+")
endif()
#To work around https://gitlab.kitware.com/cmake/cmake/issues/17512
#we need to fix the CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES variable
if(${CMAKE_VERSION} VERSION_LESS 3.10 AND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)
list(APPEND CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}")
endif()
if (NOT TARGET vtkm_cuda OR NOT TARGET vtkm::cuda)
add_library(vtkm_cuda INTERFACE)
set_target_properties(vtkm_cuda PROPERTIES EXPORT_NAME vtkm::cuda)
@ -222,13 +216,11 @@ if(VTKm_ENABLE_CUDA)
set(VTKM_CUDA_NATIVE_EXE_PROCESS_RAN_OUTPUT ${run_output} CACHE INTERNAL
"device type(s) for cuda[native]")
else()
set(VTKm_CUDA_Architecture "kepler")
message(FATAL_ERROR "Error detecting architecture flags for CUDA. Please set VTKm_CUDA_Architecture manually.")
endif()
endif()
endif()
#since when we are native we can fail, and fall back to "kepler" these have
#to happen after, and separately of the native check
if(VTKm_CUDA_Architecture STREQUAL "fermi")
set(arch_flags --generate-code=arch=compute_20,code=sm_20)
elseif(VTKm_CUDA_Architecture STREQUAL "kepler")

@ -18,7 +18,7 @@ if(VTKm_ENABLE_MPI AND NOT TARGET MPI::MPI_CXX)
#clunky but we need to make sure we use the upstream module if it exists
set(orig_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
set(CMAKE_MODULE_PATH "")
find_package(MPI MODULE)
find_package(MPI REQUIRED MODULE)
set(CMAKE_MODULE_PATH ${orig_CMAKE_MODULE_PATH})
endif()
endif()

@ -14,6 +14,10 @@ include(VTKmDeviceAdapters)
include(VTKmCPUVectorization)
include(VTKmMPI)
#-----------------------------------------------------------------------------
# INTERNAL FUNCTIONS
# No promises when used from outside VTK-m
#-----------------------------------------------------------------------------
# Utility to build a kit name from the current directory.
function(vtkm_get_kit_name kitvar)
@ -50,43 +54,6 @@ function(vtkm_pyexpander_generated_file generated_file_name)
endif()
endfunction(vtkm_pyexpander_generated_file)
#-----------------------------------------------------------------------------
# This function is not needed by the core infrastructure of VTK-m
# as we now require CMake 3.11 on windows, and for tests we compile a single
# executable for all backends, instead of compiling for each backend.
# It is currently kept around so that examples which haven't been updated
# continue to work
function(vtkm_compile_as_cuda output)
# We can't use set_source_files_properties(<> PROPERTIES LANGUAGE "CUDA")
# for the following reasons:
#
# 1. As of CMake 3.10 MSBuild cuda language support has a bug where files
# aren't passed to nvcc with the explicit '-x cu' flag which will cause
# them to be compiled without CUDA actually enabled.
# 2. If the source file is used by multiple targets(libraries/executable)
# they will all see the source file marked as being CUDA. This will cause
# tests / examples that reuse sources with different backends to use CUDA
# by mistake
#
# The result of this is that instead we will use file(GENERATE ) to construct
# a proxy cu file
set(_cuda_srcs )
foreach(_to_be_cuda_file ${ARGN})
get_filename_component(_fname_ext "${_to_be_cuda_file}" EXT)
if(_fname_ext STREQUAL ".cu")
list(APPEND _cuda_srcs "${_to_be_cuda_file}")
else()
get_filename_component(_cuda_fname "${_to_be_cuda_file}" NAME_WE)
get_filename_component(_not_cuda_fullpath "${_to_be_cuda_file}" ABSOLUTE)
list(APPEND _cuda_srcs "${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu")
file(GENERATE
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu
CONTENT "#include \"${_not_cuda_fullpath}\"")
endif()
endforeach()
set(${output} ${_cuda_srcs} PARENT_SCOPE)
endfunction()
#-----------------------------------------------------------------------------
function(vtkm_generate_export_header lib_name)
# Get the location of this library in the directory structure
@ -124,7 +91,6 @@ function(vtkm_generate_export_header lib_name)
DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix}
)
endif()
endfunction(vtkm_generate_export_header)
#-----------------------------------------------------------------------------
@ -144,22 +110,147 @@ function(vtkm_declare_headers)
vtkm_install_headers("${dir_prefix}" ${ARGN})
endfunction(vtkm_declare_headers)
#-----------------------------------------------------------------------------
# FORWARD FACING API
#-----------------------------------------------------------------------------
# Pass to consumers extra compile flags they need to add to CMAKE_CUDA_FLAGS
# to have CUDA compatibility.
#
# This is required as currently the -sm/-gencode flags when specified inside
# COMPILE_OPTIONS / target_compile_options are not propagated to the device
# linker. Instead they must be specified in CMAKE_CUDA_FLAGS
#
#
# add_library(lib_that_uses_vtkm ...)
# vtkm_add_cuda_flags(CMAKE_CUDA_FLAGS)
# target_link_libraries(lib_that_uses_vtkm PRIVATE vtkm_filter)
#
function(vtkm_get_cuda_flags settings_var)
if(TARGET vtkm::cuda)
get_property(arch_flags
TARGET vtkm::cuda
PROPERTY INTERFACE_CUDA_Architecture_Flags)
set(${settings_var} "${${settings_var}} ${arch_flags}" PARENT_SCOPE)
endif()
endfunction()
#-----------------------------------------------------------------------------
# Add a relevant information to target that wants to use VTK-m.
#
# This is a higher order function to allow build-systems that use VTK-m
# to compose add_library/add_executable and the required information to have
# VTK-m enabled.
#
# vtkm_add_target_information(
# target
# [ MODIFY_CUDA_FLAGS ]
# [ EXTENDS_VTKM ]
# [ DEVICE_SOURCES <source_list>
# )
#
# Usage:
# add_library(lib_that_uses_vtkm STATIC a.cxx)
# vtkm_add_target_information(lib_that_uses_vtkm
# MODIFY_CUDA_FLAGS
# DEVICE_SOURCES a.cxx
# )
# target_link_libraries(lib_that_uses_vtkm PRIVATE vtkm_filter)
#
# MODIFY_CUDA_FLAGS: If enabled will add the required -arch=<ver> flags
# that VTK-m was compiled with. This functionality is also provided by the
# the standalone `vtkm_get_cuda_flags` function.
#
# DEVICE_SOURCES: The collection of source files that are used by `target` that
# need to be marked as going to a special compiler for certain device adapters
# such as CUDA.
#
# EXTENDS_VTKM: Some programming models have restrictions on how types can be extended.
# For example CUDA doesn't allow device side calls across dynamic library boundaries,
# and requires all polymorphic classes to be reachable at dynamic library/executable
# link time.
#
# To accommodate these restrictions we need to handle the following allowable
# use-cases:
# Object library: do nothing, zero restrictions
# Executable: do nothing, zero restrictions
# Static library: do nothing, zero restrictions
# Dynamic library:
# -> Wanting to extend VTK-m and provide these types to consumers. This
# is supported when CUDA isn't enabled. Otherwise we need to ERROR!
# -> Wanting to use VTK-m as implementation detail, doesn't expose VTK-m
# types to consumers. This is supported no matter if CUDA is enabled.
#
# For most consumers they can ignore the `EXTENDS_VTKM` property as the default
# will be correct.
#
#
function(vtkm_add_target_information uses_vtkm_target)
set(options MODIFY_CUDA_FLAGS EXTENDS_VTKM)
set(multiValueArgs DEVICE_SOURCES)
cmake_parse_arguments(VTKm_TI
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
# Validate that following:
# - We are building with CUDA enabled.
# - We are building a VTK-m library or a library that wants cross library
# device calls.
#
# This is required as CUDA currently doesn't support device side calls across
# dynamic library boundaries.
if(TARGET vtkm::cuda)
get_target_property(lib_type ${uses_vtkm_target} TYPE)
get_target_property(requires_static vtkm::cuda INTERFACE_REQUIRES_STATIC_BUILDS)
if(requires_static AND ${lib_type} STREQUAL "SHARED_LIBRARY")
#We provide different error messages based on if we are building VTK-m
#or being called by a consumer of VTK-m. We use PROJECT_NAME so that we
#produce the correct error message when VTK-m is a subdirectory include
#of another project
if(PROJECT_NAME STREQUAL "VTKm")
message(SEND_ERROR "${uses_vtkm_target} needs to be built STATIC as CUDA doesn't"
" support virtual methods across dynamic library boundaries. You"
" need to set the CMake option BUILD_SHARED_LIBS to `OFF`.")
else()
message(SEND_ERROR "${uses_vtkm_target} needs to be built STATIC as CUDA doesn't"
" support virtual methods across dynamic library boundaries. You"
" should either explicitly call add_library with the `STATIC` keyword"
" or set the CMake option BUILD_SHARED_LIBS to `OFF`.")
endif()
endif()
set_source_files_properties(${VTKm_TI_DEVICE_SOURCES} PROPERTIES LANGUAGE "CUDA")
endif()
set_target_properties(${uses_vtkm_target} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${uses_vtkm_target} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
if(VTKm_TI_MODIFY_CUDA_FLAGS)
vtkm_get_cuda_flags(CMAKE_CUDA_FLAGS)
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} PARENT_SCOPE)
endif()
endfunction()
#-----------------------------------------------------------------------------
# Add a VTK-m library. The name of the library will match the "kit" name
# (e.g. vtkm_rendering) unless the NAME argument is given.
#
# vtkm_library(
# [NAME <name>]
# [ NAME <name> ]
# [ OBJECT | STATIC | SHARED ]
# SOURCES <source_list>
# TEMPLATE_SOURCES <.hxx >
# HEADERS <header list>
# [WRAP_FOR_CUDA <source_list>]
# [ DEVICE_SOURCES <source_list> ]
# )
function(vtkm_library)
set(options OBJECT STATIC SHARED)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES HEADERS TEMPLATE_SOURCES WRAP_FOR_CUDA)
set(multiValueArgs SOURCES HEADERS TEMPLATE_SOURCES DEVICE_SOURCES)
cmake_parse_arguments(VTKm_LIB
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
@ -183,45 +274,20 @@ function(vtkm_library)
${VTKm_LIB_SOURCES}
${VTKm_LIB_HEADERS}
${VTKm_LIB_TEMPLATE_SOURCES}
${VTKm_LIB_WRAP_FOR_CUDA}
${VTKm_LIB_DEVICE_SOURCES}
)
# Validate that following:
# - We are building with CUDA enabled.
# - We are building a VTK-m library or a library that wants cross library
# device calls.
#
# This is required as CUDA currently doesn't support device side calls across
# dynamic library boundaries.
if(TARGET vtkm::cuda)
get_target_property(lib_type ${lib_name} TYPE)
get_target_property(requires_static vtkm::cuda INTERFACE_REQUIRES_STATIC_BUILDS)
if(requires_static AND ${lib_type} STREQUAL "SHARED_LIBRARY")
message(FATAL_ERROR "${lib_name} Needs to be built STATIC as CUDA doesn't"
" support virtual methods across dynamic library boundaries. You"
" need to set the CMake option BUILD_SHARED_LIBS to OFF.")
endif()
# We are a validate target type for CUDA compilation, so mark all the requested
# sources to be compiled by CUDA
set_source_files_properties(${VTKm_LIB_WRAP_FOR_CUDA} PROPERTIES LANGUAGE "CUDA")
vtkm_add_target_information(${lib_name}
DEVICE_SOURCES ${VTKm_LIB_DEVICE_SOURCES}
)
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()
#when building either static or shared we want pic code
set_target_properties(${lib_name} PROPERTIES POSITION_INDEPENDENT_CODE ON)
#specify when building with cuda we want separable compilation
set_property(TARGET ${lib_name} PROPERTY CUDA_SEPARABLE_COMPILATION ON)
#specify where to place the built library
set_property(TARGET ${lib_name} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
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})
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()
# allow the static cuda runtime find the driver (libcuda.dyllib) at runtime.
if(APPLE)
@ -268,209 +334,3 @@ function(vtkm_library)
)
endfunction(vtkm_library)
#-----------------------------------------------------------------------------
# Declare unit tests, which should be in the same directory as a kit
# (package, module, whatever you call it). Usage:
#
# vtkm_unit_tests(
# NAME
# SOURCES <source_list>
# BACKEND <type>
# LIBRARIES <dependent_library_list>
# DEFINES <target_compile_definitions>
# TEST_ARGS <argument_list>
# MPI
# ALL_BACKENDS
# <options>
# )
#
# [BACKEND]: mark all source files as being compiled with the proper defines
# to make this backend the default backend
# If the backend is specified as CUDA it will also imply all
# sources should be treated as CUDA sources
# The backend name will also be added to the executable name
# so you can test multiple backends easily
#
# [LIBRARIES] : extra libraries that this set of tests need to link too
#
# [DEFINES] : extra defines that need to be set for all unit test sources
#
# [TEST_ARGS] : arguments that should be passed on the command line to the
# test executable
#
# [MPI] : when specified, the tests should be run in parallel if
# MPI is enabled.
# [ALL_BACKENDS] : when specified, the tests would test against all enabled
# backends. BACKEND argument would be ignored.
#
function(vtkm_unit_tests)
if (NOT VTKm_ENABLE_TESTING)
return()
endif()
set(options)
set(global_options ${options} MPI ALL_BACKENDS)
set(oneValueArgs BACKEND NAME)
set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
cmake_parse_arguments(VTKm_UT
"${global_options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES})
set(test_prog)
set(backend ${VTKm_UT_BACKEND})
set(enable_all_backends ${VTKm_UT_ALL_BACKENDS})
set(all_backends Serial)
if (VTKm_ENABLE_CUDA)
list(APPEND all_backends Cuda)
endif()
if (VTKm_ENABLE_TBB)
list(APPEND all_backends TBB)
endif()
if (VTKm_ENABLE_OPENMP)
list(APPEND all_backends OpenMP)
endif()
if(VTKm_UT_NAME)
set(test_prog "${VTKm_UT_NAME}")
else()
vtkm_get_kit_name(kit)
set(test_prog "UnitTests_${kit}")
endif()
if(backend)
set(test_prog "${test_prog}_${backend}")
set(all_backends ${backend})
elseif(NOT enable_all_backends)
set (all_backends "NO_BACKEND")
endif()
if(VTKm_UT_MPI)
# for MPI tests, suffix test name and add MPI_Init/MPI_Finalize calls.
set(test_prog "${test_prog}_mpi")
set(extraArgs EXTRA_INCLUDE "vtkm/cont/testing/Testing.h"
FUNCTION "vtkm::cont::testing::Environment env")
else()
set(extraArgs)
endif()
#the creation of the test source list needs to occur before the labeling as
#cuda. This is so that we get the correctly named entry points generated
create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES} ${extraArgs})
#if all backends are enabled, we can use cuda compiler to handle all possible backends.
if(TARGET vtkm::cuda AND (backend STREQUAL "Cuda" OR enable_all_backends))
set_source_files_properties(${VTKm_UT_SOURCES} PROPERTIES LANGUAGE "CUDA")
endif()
add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES})
set_property(TARGET ${test_prog} PROPERTY CUDA_SEPARABLE_COMPILATION ON)
set_property(TARGET ${test_prog} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
set_property(TARGET ${test_prog} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
set_property(TARGET ${test_prog} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH})
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
set_property(TARGET ${test_prog} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${test_prog} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()
#Starting in CMake 3.13, cmake will properly drop duplicate libraries
#from the link line so this workaround can be dropped
if (CMAKE_VERSION VERSION_LESS 3.13 AND "vtkm_rendering" IN_LIST VTKm_UT_LIBRARIES)
list(REMOVE_ITEM VTKm_UT_LIBRARIES "vtkm_cont")
target_link_libraries(${test_prog} PRIVATE ${VTKm_UT_LIBRARIES})
else()
target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
endif()
target_compile_definitions(${test_prog} PRIVATE ${VTKm_UT_DEFINES})
foreach(current_backend ${all_backends})
set (device_command_line_argument --device=${current_backend})
if (current_backend STREQUAL "NO_BACKEND")
set (current_backend "")
set(device_command_line_argument "")
endif()
string(TOUPPER "${current_backend}" upper_backend)
foreach (test ${VTKm_UT_SOURCES})
get_filename_component(tname ${test} NAME_WE)
if(VTKm_UT_MPI AND VTKm_ENABLE_MPI)
add_test(NAME ${tname}${upper_backend}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${test_prog}> ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
${MPIEXEC_POSTFLAGS}
)
else()
add_test(NAME ${tname}${upper_backend}
COMMAND ${test_prog} ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
)
endif()
#determine the timeout for all the tests based on the backend. CUDA tests
#generally require more time because of kernel generation.
if (current_backend STREQUAL "Cuda")
set(timeout 1500)
else()
set(timeout 180)
endif()
if(current_backend STREQUAL "OpenMP")
#We need to have all OpenMP tests run serially as they
#will uses all the system cores, and we will cause a N*N thread
#explosion which causes the tests to run slower than when run
#serially
set(run_serial True)
else()
set(run_serial False)
endif()
set_tests_properties("${tname}${upper_backend}" PROPERTIES
TIMEOUT ${timeout}
RUN_SERIAL ${run_serial}
)
set_tests_properties("${tname}${upper_backend}" PROPERTIES
FAIL_REGULAR_EXPRESSION "runtime error"
)
endforeach (test)
endforeach(current_backend)
endfunction(vtkm_unit_tests)
# -----------------------------------------------------------------------------
# vtkm_parse_test_options(varname options)
# INTERNAL: Parse options specified for individual tests.
#
# Parses the arguments to separate out options specified after the test name
# separated by a comma e.g.
#
# TestName,Option1,Option2
#
# For every option in options, this will set _TestName_Option1,
# _TestName_Option2, etc in the parent scope.
#
function(vtkm_parse_test_options varname options)
set(names)
foreach(arg IN LISTS ARGN)
set(test_name ${arg})
set(test_options)
if(test_name AND "x${test_name}" MATCHES "^x([^,]*),(.*)$")
set(test_name "${CMAKE_MATCH_1}")
string(REPLACE "," ";" test_options "${CMAKE_MATCH_2}")
endif()
foreach(opt IN LISTS test_options)
list(FIND options "${opt}" index)
if(index EQUAL -1)
message(WARNING "Unknown option '${opt}' specified for test '${test_name}'")
else()
set(_${test_name}_${opt} TRUE PARENT_SCOPE)
endif()
endforeach()
list(APPEND names ${test_name})
endforeach()
set(${varname} ${names} PARENT_SCOPE)
endfunction()

@ -0,0 +1,203 @@
##============================================================================
## 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.
##============================================================================
include(VTKmWrappers)
#-----------------------------------------------------------------------------
# Declare unit tests, which should be in the same directory as a kit
# (package, module, whatever you call it). Usage:
#
# vtkm_unit_tests(
# NAME
# SOURCES <source_list>
# LIBRARIES <dependent_library_list>
# DEFINES <target_compile_definitions>
# TEST_ARGS <argument_list>
# MPI
# ALL_BACKENDS
# <options>
# )
#
# [LIBRARIES] : extra libraries that this set of tests need to link too
#
# [DEFINES] : extra defines that need to be set for all unit test sources
#
# [TEST_ARGS] : arguments that should be passed on the command line to the
# test executable
#
# [MPI] : when specified, the tests should be run in parallel if
# MPI is enabled.
# [ALL_BACKENDS] : when specified, the tests would test against all enabled
# backends. Otherwise we expect the tests to manage the
# backends at runtime.
#
function(vtkm_unit_tests)
if (NOT VTKm_ENABLE_TESTING)
return()
endif()
set(options)
set(global_options ${options} MPI ALL_BACKENDS)
set(oneValueArgs BACKEND NAME)
set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
cmake_parse_arguments(VTKm_UT
"${global_options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES})
set(test_prog)
set(per_device_command_line_arguments "")
set(per_device_suffix "")
set(per_device_timeout 180)
set(per_device_serial FALSE)
set(enable_all_backends ${VTKm_UT_ALL_BACKENDS})
if(enable_all_backends)
set(per_device_command_line_arguments --device=serial)
set(per_device_suffix "SERIAL")
if (VTKm_ENABLE_CUDA)
list(APPEND per_device_command_line_arguments --device=cuda)
list(APPEND per_device_suffix "CUDA")
#CUDA tests generally require more time because of kernel generation.
list(APPEND per_device_timeout 1500)
list(APPEND per_device_serial FALSE)
endif()
if (VTKm_ENABLE_TBB)
list(APPEND per_device_command_line_arguments --device=tbb)
list(APPEND per_device_suffix "TBB")
list(APPEND per_device_timeout 180)
list(APPEND per_device_serial FALSE)
endif()
if (VTKm_ENABLE_OPENMP)
list(APPEND per_device_command_line_arguments --device=openmp)
list(APPEND per_device_suffix "OPENMP")
list(APPEND per_device_timeout 180)
#We need to have all OpenMP tests run serially as they
#will uses all the system cores, and we will cause a N*N thread
#explosion which causes the tests to run slower than when run
#serially
list(APPEND per_device_serial TRUE)
endif()
endif()
if(VTKm_UT_NAME)
set(test_prog "${VTKm_UT_NAME}")
else()
vtkm_get_kit_name(kit)
set(test_prog "UnitTests_${kit}")
endif()
if(VTKm_UT_MPI)
# for MPI tests, suffix test name and add MPI_Init/MPI_Finalize calls.
set(test_prog "${test_prog}_mpi")
set(extraArgs EXTRA_INCLUDE "vtkm/cont/testing/Testing.h"
FUNCTION "vtkm::cont::testing::Environment env")
else()
set(extraArgs)
endif()
#the creation of the test source list needs to occur before the labeling as
#cuda. This is so that we get the correctly named entry points generated
create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES} ${extraArgs})
add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES})
target_compile_definitions(${test_prog} PRIVATE ${VTKm_UT_DEFINES})
#if all backends are enabled, we can use cuda compiler to handle all possible backends.
set(device_sources )
if(TARGET vtkm::cuda AND enable_all_backends)
set(device_sources ${VTKm_UT_SOURCES})
endif()
vtkm_add_target_information(${test_prog} DEVICE_SOURCES ${device_sources})
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
set_property(TARGET ${test_prog} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${test_prog} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()
set_property(TARGET ${test_prog} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
set_property(TARGET ${test_prog} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
set_property(TARGET ${test_prog} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH})
target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
foreach(index RANGE per_device_command_line_arguments)
if(per_device_command_line_arguments STREQUAL "")
set(device_command_line_argument ${per_device_command_line_arguments})
set(upper_backend ${per_device_suffix})
set(timeout ${per_device_timeout})
set(run_serial ${per_device_serial})
else()
list(GET per_device_command_line_arguments ${index} device_command_line_argument)
list(GET per_device_suffix ${index} upper_backend)
list(GET per_device_timeout ${index} timeout)
list(GET per_device_serial ${index} run_serial)
endif()
foreach (test ${VTKm_UT_SOURCES})
get_filename_component(tname ${test} NAME_WE)
if(VTKm_UT_MPI AND VTKm_ENABLE_MPI)
add_test(NAME ${tname}${upper_backend}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${test_prog}> ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
${MPIEXEC_POSTFLAGS}
)
else()
add_test(NAME ${tname}${upper_backend}
COMMAND ${test_prog} ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
)
endif()
set_tests_properties("${tname}${upper_backend}" PROPERTIES
TIMEOUT ${timeout}
RUN_SERIAL ${run_serial}
FAIL_REGULAR_EXPRESSION "runtime error"
)
endforeach()
endforeach()
endfunction(vtkm_unit_tests)
# -----------------------------------------------------------------------------
# vtkm_parse_test_options(varname options)
# INTERNAL: Parse options specified for individual tests.
#
# Parses the arguments to separate out options specified after the test name
# separated by a comma e.g.
#
# TestName,Option1,Option2
#
# For every option in options, this will set _TestName_Option1,
# _TestName_Option2, etc in the parent scope.
#
function(vtkm_parse_test_options varname options)
set(names)
foreach(arg IN LISTS ARGN)
set(test_name ${arg})
set(test_options)
if(test_name AND "x${test_name}" MATCHES "^x([^,]*),(.*)$")
set(test_name "${CMAKE_MATCH_1}")
string(REPLACE "," ";" test_options "${CMAKE_MATCH_2}")
endif()
foreach(opt IN LISTS test_options)
list(FIND options "${opt}" index)
if(index EQUAL -1)
message(WARNING "Unknown option '${opt}' specified for test '${test_name}'")
else()
set(_${test_name}_${opt} TRUE PARENT_SCOPE)
endif()
endforeach()
list(APPEND names ${test_name})
endforeach()
set(${varname} ${names} PARENT_SCOPE)
endfunction()

@ -143,6 +143,9 @@ include(VTKmCompilerFlags)
#-----------------------------------------------------------------------------
# We include the wrappers unconditionally as VTK-m expects the function to
# always exist (and early terminate when testing is disabled).
include(testing/VTKmTestWrappers)
if (VTKm_ENABLE_TESTING)
enable_testing()
# Only include CTest if it has not been included by a superproject. The
@ -155,6 +158,7 @@ if (VTKm_ENABLE_TESTING)
mark_as_advanced(BUILD_TESTING)
endif()
configure_file(${VTKm_SOURCE_DIR}/CTestCustom.cmake.in
${VTKm_BINARY_DIR}/CTestCustom.cmake @ONLY)
@ -187,7 +191,7 @@ add_subdirectory(vtkm)
#-----------------------------------------------------------------------------
# Build documentation
if (VTKm_ENABLE_DOCUMENTATION)
include(CMake/VTKmBuildDocumentation.cmake)
include(VTKmBuildDocumentation)
endif()
#-----------------------------------------------------------------------------

@ -63,9 +63,10 @@ VTK-m Requires:
+ XCode 5.0+
+ MSVC 2015+
+ [CMake](http://www.cmake.org/download/)
+ CMake 3.8+ (for any build)
+ CMake 3.9+ (for CUDA build or OpenMP build)
+ CMake 3.8+
+ CMake 3.9+ (for OpenMP support)
+ CMake 3.11+ (for Visual Studio generator)
+ CMake 3.13+ (for CUDA support)
Optional dependencies are:

@ -105,7 +105,7 @@ if sortOpt:
keys = sorted(keys, key=lambda k: benchmarks[k].mean)
print("# Summary: (%s)"%filename)
print("%-9s\t%-9s\t%-s"%("Mean", "Stdev", "Benchmark (type)"))
print("%-9s\t%-9s\t%-9s\t%-s"%("Mean", "Stdev", "Stdev%", "Benchmark (type)"))
for key in keys:
data = benchmarks[key]
print("%9.6f\t%9.6f\t%s (%s)"%(data.mean, data.stdDev, key.name, key.type))
print("%9.6f\t%9.6f\t%9.6f\t%s (%s)"%(data.mean, data.stdDev, data.stdDev / data.mean * 100., key.name, key.type))

@ -12,11 +12,12 @@
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/ImplicitFunctionHandle.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
@ -292,6 +293,40 @@ private:
const T2* Function2;
};
struct PassThroughFunctor
{
template <typename T>
VTKM_EXEC_CONT T operator()(const T& x) const
{
return x;
}
};
template <typename ArrayHandleType>
using ArrayHandlePassThrough =
vtkm::cont::ArrayHandleTransform<ArrayHandleType, PassThroughFunctor, PassThroughFunctor>;
template <typename ArrayHandleType>
using BMArrayHandleMultiplexer =
vtkm::ListTagApply<vtkm::ListTagAppend<vtkm::cont::internal::ArrayHandleMultiplexerDefaultArrays<
typename ArrayHandleType::ValueType>,
ArrayHandlePassThrough<ArrayHandleType>>,
vtkm::cont::ArrayHandleMultiplexer>;
template <typename ArrayHandleType>
BMArrayHandleMultiplexer<ArrayHandleType> make_ArrayHandleMultiplexer0(const ArrayHandleType& array)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return BMArrayHandleMultiplexer<ArrayHandleType>(array);
}
template <typename ArrayHandleType>
BMArrayHandleMultiplexer<ArrayHandleType> make_ArrayHandleMultiplexerN(const ArrayHandleType& array)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return BMArrayHandleMultiplexer<ArrayHandleType>(ArrayHandlePassThrough<ArrayHandleType>(array));
}
struct ValueTypes : vtkm::ListTagBase<vtkm::Float32, vtkm::Float64>
{
};
@ -308,10 +343,6 @@ class BenchmarkFieldAlgorithms
using Timer = vtkm::cont::Timer;
using ValueVariantHandle = vtkm::cont::VariantArrayHandleBase<ValueTypes>;
using InterpVariantHandle = vtkm::cont::VariantArrayHandleBase<InterpValueTypes>;
using EdgeIdVariantHandle = vtkm::cont::VariantArrayHandleBase<vtkm::TypeListTagId2>;
private:
template <typename Value, typename DeviceAdapter>
struct BenchBlackScholes
@ -349,8 +380,10 @@ private:
this->OptionYears = vtkm::cont::make_ArrayHandle(this->years);
}
VTKM_CONT
vtkm::Float64 operator()()
template <typename StockPriceType, typename OptionStrikeType, typename OptionYearsType>
VTKM_CONT static vtkm::Float64 Run(const StockPriceType& stockPrice,
const OptionStrikeType& optionStrike,
const OptionYearsType& optionYears)
{
vtkm::cont::ArrayHandle<Value> callResultHandle, putResultHandle;
const Value RISKFREE = 0.02f;
@ -361,12 +394,17 @@ private:
BlackScholes<Value> worklet(RISKFREE, VOLATILITY);
vtkm::worklet::DispatcherMapField<BlackScholes<Value>> dispatcher(worklet);
dispatcher.Invoke(
this->StockPrice, this->OptionStrike, this->OptionYears, callResultHandle, putResultHandle);
dispatcher.Invoke(stockPrice, optionStrike, optionYears, callResultHandle, putResultHandle);
return timer.GetElapsedTime();
}
VTKM_CONT
vtkm::Float64 operator()()
{
return this->Run(this->StockPrice, this->OptionStrike, this->OptionYears);
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
@ -387,29 +425,66 @@ private:
VTKM_CONT
vtkm::Float64 operator()()
{
ValueVariantHandle dstocks(this->StockPrice);
ValueVariantHandle dstrikes(this->OptionStrike);
ValueVariantHandle doptions(this->OptionYears);
vtkm::cont::ArrayHandle<Value> callResultHandle, putResultHandle;
const Value RISKFREE = 0.02f;
const Value VOLATILITY = 0.30f;
Timer timer{ DeviceAdapter() };
timer.Start();
BlackScholes<Value> worklet(RISKFREE, VOLATILITY);
vtkm::worklet::DispatcherMapField<BlackScholes<Value>> dispatcher(worklet);
dispatcher.Invoke(dstocks, dstrikes, doptions, callResultHandle, putResultHandle);
return timer.GetElapsedTime();
return this->Run(vtkm::cont::make_ArrayHandleVirtual(this->StockPrice),
vtkm::cont::make_ArrayHandleVirtual(this->OptionStrike),
vtkm::cont::make_ArrayHandleVirtual(this->OptionYears));
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
template <typename Value, typename DeviceAdapter>
struct BenchBlackScholesMultiplexer0 : public BenchBlackScholes<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
return this->Run(make_ArrayHandleMultiplexer0(this->StockPrice),
make_ArrayHandleMultiplexer0(this->OptionStrike),
make_ArrayHandleMultiplexer0(this->OptionYears));
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexer0(this->StockPrice)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchBlackScholesMultiplexerN : public BenchBlackScholes<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
return this->Run(make_ArrayHandleMultiplexerN(this->StockPrice),
make_ArrayHandleMultiplexerN(this->OptionStrike),
make_ArrayHandleMultiplexerN(this->OptionYears));
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexerN(this->StockPrice)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
VTKM_MAKE_BENCHMARK(BlackScholes, BenchBlackScholes);
VTKM_MAKE_BENCHMARK(BlackScholesDynamic, BenchBlackScholesDynamic);
VTKM_MAKE_BENCHMARK(BlackScholesMultiplexer0, BenchBlackScholesMultiplexer0);
VTKM_MAKE_BENCHMARK(BlackScholesMultiplexerN, BenchBlackScholesMultiplexerN);
template <typename Value, typename DeviceAdapter>
struct BenchMath
@ -470,13 +545,11 @@ private:
VTKM_CONT
vtkm::Float64 operator()()
{
using MathTypes = vtkm::ListTagBase<vtkm::Vec<vtkm::Float32, 3>, vtkm::Vec<vtkm::Float64, 3>>;
vtkm::cont::ArrayHandle<Value> temp1;
vtkm::cont::ArrayHandle<Value> temp2;
vtkm::cont::VariantArrayHandleBase<MathTypes> dinput(this->InputHandle);
ValueVariantHandle dtemp1(temp1);
ValueVariantHandle dtemp2(temp2);
auto dinput = vtkm::cont::make_ArrayHandleVirtual(this->InputHandle);
auto dtemp1 = vtkm::cont::make_ArrayHandleVirtual(temp1);
auto dtemp2 = vtkm::cont::make_ArrayHandleVirtual(temp2);
Timer timer{ DeviceAdapter() };
timer.Start();
@ -493,8 +566,84 @@ private:
virtual std::string Type() const { return std::string("Dynamic"); }
};
template <typename Value, typename DeviceAdapter>
struct BenchMathMultiplexer0 : public BenchMath<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::ArrayHandle<Value> temp1;
vtkm::cont::ArrayHandle<Value> temp2;
auto mInput = make_ArrayHandleMultiplexer0(this->InputHandle);
auto mTemp1 = make_ArrayHandleMultiplexer0(temp1);
auto mTemp2 = make_ArrayHandleMultiplexer0(temp2);
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::Invoker invoke(DeviceAdapter{});
invoke(Mag{}, mInput, mTemp1);
invoke(Sin{}, mTemp1, mTemp2);
invoke(Square{}, mTemp2, mTemp1);
invoke(Cos{}, mTemp1, mTemp2);
return timer.GetElapsedTime();
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexer0(this->InputHandle)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchMathMultiplexerN : public BenchMath<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::ArrayHandle<Value> temp1;
vtkm::cont::ArrayHandle<Value> temp2;
auto mInput = make_ArrayHandleMultiplexerN(this->InputHandle);
auto mTemp1 = make_ArrayHandleMultiplexerN(temp1);
auto mTemp2 = make_ArrayHandleMultiplexerN(temp2);
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::Invoker invoke(DeviceAdapter{});
invoke(Mag{}, mInput, mTemp1);
invoke(Sin{}, mTemp1, mTemp2);
invoke(Square{}, mTemp2, mTemp1);
invoke(Cos{}, mTemp1, mTemp2);
return timer.GetElapsedTime();
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexerN(this->InputHandle)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
VTKM_MAKE_BENCHMARK(Math, BenchMath);
VTKM_MAKE_BENCHMARK(MathDynamic, BenchMathDynamic);
VTKM_MAKE_BENCHMARK(MathMultiplexer0, BenchMathMultiplexer0);
VTKM_MAKE_BENCHMARK(MathMultiplexerN, BenchMathMultiplexerN);
template <typename Value, typename DeviceAdapter>
struct BenchFusedMath
@ -517,19 +666,22 @@ private:
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
}
VTKM_CONT
vtkm::Float64 operator()()
template <typename InputHandleType>
VTKM_CONT static vtkm::Float64 Run(const InputHandleType& inputHandle)
{
vtkm::cont::ArrayHandle<Value> result;
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapField<FusedMath> dispatcher;
dispatcher.Invoke(this->InputHandle, result);
dispatcher.Invoke(inputHandle, result);
return timer.GetElapsedTime();
}
VTKM_CONT
vtkm::Float64 operator()() { return this->Run(this->InputHandle); }
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
@ -550,25 +702,60 @@ private:
VTKM_CONT
vtkm::Float64 operator()()
{
using MathTypes = vtkm::ListTagBase<vtkm::Vec<vtkm::Float32, 3>, vtkm::Vec<vtkm::Float64, 3>>;
vtkm::cont::VariantArrayHandleBase<MathTypes> dinput(this->InputHandle);
vtkm::cont::ArrayHandle<Value, StorageTag> result;
Timer timer{ DeviceAdapter() };
timer.Start();
vtkm::worklet::DispatcherMapField<FusedMath> dispatcher;
dispatcher.Invoke(dinput, result);
return timer.GetElapsedTime();
return this->Run(vtkm::cont::make_ArrayHandleVirtual(this->InputHandle));
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
template <typename Value, typename DeviceAdapter>
struct BenchFusedMathMultiplexer0 : public BenchFusedMath<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
return this->Run(make_ArrayHandleMultiplexer0(this->InputHandle));
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexer0(this->InputHandle)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
template <typename Value, typename DeviceAdapter>
struct BenchFusedMathMultiplexerN : public BenchFusedMath<Value, DeviceAdapter>
{
VTKM_CONT
vtkm::Float64 operator()()
{
return this->Run(make_ArrayHandleMultiplexerN(this->InputHandle));
}
virtual std::string Type() const
{
std::stringstream desc;
desc << "Multiplexer-"
<< make_ArrayHandleMultiplexerN(this->InputHandle)
.GetStorage()
.GetArrayHandleVariant()
.GetIndex();
return desc.str();
}
};
VTKM_MAKE_BENCHMARK(FusedMath, BenchFusedMath);
VTKM_MAKE_BENCHMARK(FusedMathDynamic, BenchFusedMathDynamic);
VTKM_MAKE_BENCHMARK(FusedMathMultiplexer0, BenchFusedMathMultiplexer0);
VTKM_MAKE_BENCHMARK(FusedMathMultiplexerN, BenchFusedMathMultiplexerN);
template <typename Value, typename DeviceAdapter>
struct BenchEdgeInterp
@ -655,9 +842,9 @@ private:
VTKM_CONT
vtkm::Float64 operator()()
{
InterpVariantHandle dfield(this->FieldHandle);
ValueVariantHandle dweight(this->WeightHandle);
EdgeIdVariantHandle dedges(this->EdgePairHandle);
auto dfield = vtkm::cont::make_ArrayHandleVirtual(this->FieldHandle);
auto dweight = vtkm::cont::make_ArrayHandleVirtual(this->WeightHandle);
auto dedges = vtkm::cont::make_ArrayHandleVirtual(this->EdgePairHandle);
vtkm::cont::ArrayHandle<Value> result;
Timer timer{ DeviceAdapter() };
@ -877,6 +1064,8 @@ public:
std::cout << DIVIDER << "\nBenchmarking BlackScholes\n";
VTKM_RUN_BENCHMARK(BlackScholes, ValueTypes(), id);
VTKM_RUN_BENCHMARK(BlackScholesDynamic, ValueTypes(), id);
VTKM_RUN_BENCHMARK(BlackScholesMultiplexer0, ValueTypes(), id);
VTKM_RUN_BENCHMARK(BlackScholesMultiplexerN, ValueTypes(), id);
}
if (benchmarks & MATH)
@ -884,6 +1073,8 @@ public:
std::cout << DIVIDER << "\nBenchmarking Multiple Math Worklets\n";
VTKM_RUN_BENCHMARK(Math, ValueTypes(), id);
VTKM_RUN_BENCHMARK(MathDynamic, ValueTypes(), id);
VTKM_RUN_BENCHMARK(MathMultiplexer0, ValueTypes(), id);
VTKM_RUN_BENCHMARK(MathMultiplexerN, ValueTypes(), id);
}
if (benchmarks & FUSED_MATH)
@ -891,6 +1082,8 @@ public:
std::cout << DIVIDER << "\nBenchmarking Single Fused Math Worklet\n";
VTKM_RUN_BENCHMARK(FusedMath, ValueTypes(), id);
VTKM_RUN_BENCHMARK(FusedMathDynamic, ValueTypes(), id);
VTKM_RUN_BENCHMARK(FusedMathMultiplexer0, ValueTypes(), id);
VTKM_RUN_BENCHMARK(FusedMathMultiplexerN, ValueTypes(), id);
}
if (benchmarks & INTERPOLATE_FIELD)

@ -283,6 +283,7 @@ public:
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;

@ -22,16 +22,10 @@ function(add_benchmark)
set_target_properties(${exe_name} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH}
CXX_VISIBILITY_PRESET "hidden"
CUDA_VISIBILITY_PRESET "hidden"
CUDA_SEPARABLE_COMPILATION ON
)
set_property(TARGET ${exe_name} PROPERTY "hidden")
if (TARGET vtkm::cuda)
set_source_files_properties(${VTKm_AB_FILE} PROPERTIES LANGUAGE "CUDA")
set_target_properties(${exe_name} PROPERTIES
CUDA_VISIBILITY_PRESET "hidden"
CUDA_SEPARABLE_COMPILATION ON
)
endif()
vtkm_add_target_information(${exe_name} DEVICE_SOURCES ${VTKm_AB_FILE})
endfunction()
set(benchmarks
@ -45,7 +39,7 @@ set(benchmarks
)
foreach (benchmark ${benchmarks})
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_filter vtkm_cont)
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_filter)
endforeach ()
if(TARGET vtkm_rendering)

@ -0,0 +1,145 @@
Add ability to test exact neighbor offset locations in BoundaryState.
The following methods:
```
BoundaryState::InXBoundary
BoundaryState::InYBoundary
BoundaryState::InZBoundary
BoundaryState::InBoundary
```
have been renamed to:
```
BoundaryState::IsRadiusInXBoundary
BoundaryState::IsRadiusInYBoundary
BoundaryState::IsRadiusInZBoundary
BoundaryState::IsRadiusInBoundary
```
to distinguish them from the new methods:
```
BoundaryState::IsNeighborInXBoundary
BoundaryState::IsNeighborInYBoundary
BoundaryState::IsNeighborInZBoundary
BoundaryState::IsNeighborInBoundary
```
which check a specific neighbor sample offset instead of a full radius.
The method `BoundaryState::ClampNeighborIndex` has also been added, which clamps
a 3D neighbor offset vector to the dataset boundaries.
This allows iteration through only the valid points in a neighborhood using
either of the following patterns:
Using `ClampNeighborIndex` to restrict the iteration space:
```
struct MyWorklet : public vtkm::worklet::WorkletPointNeighborhood
{
public:
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
using ExecutionSignature = void(_2, Boundary, _3);
template <typename InNeighborhoodT, typename OutDataT>
VTKM_EXEC void operator()(const InNeighborhoodT& inData,
const vtkm::exec::BoundaryState &boundary,
OutDataT& outData) const
{
// Clamp the radius to the dataset bounds (discard out-of-bounds points).
const auto minRadius = boundary.ClampNeighborIndex({-10, -10, -10});
const auto maxRadius = boundary.ClampNeighborIndex({10, 10, 10});
for (vtkm::IdComponent k = minRadius[2]; k <= maxRadius[2]; ++k)
{
for (vtkm::IdComponent j = minRadius[1]; j <= maxRadius[1]; ++j)
{
for (vtkm::IdComponent i = minRadius[0]; i <= maxRadius[0]; ++i)
{
outData = doSomeConvolution(i, j, k, outdata, inData.Get(i, j, k));
}
}
}
}
};
```
or, using `IsNeighborInBoundary` methods to skip out-of-bounds loops:
```
struct MyWorklet : public vtkm::worklet::WorkletPointNeighborhood
{
public:
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
using ExecutionSignature = void(_2, Boundary, _3);
template <typename InNeighborhoodT, typename OutDataT>
VTKM_EXEC void operator()(const InNeighborhoodT& inData,
const vtkm::exec::BoundaryState &boundary,
OutDataT& outData) const
{
for (vtkm::IdComponent k = -10; k <= 10; ++k)
{
if (!boundary.IsNeighborInZBoundary(k))
{
continue;
}
for (vtkm::IdComponent j = -10; j <= 10; ++j)
{
if (!boundary.IsNeighborInYBoundary(j))
{
continue;
}
for (vtkm::IdComponent i = -10; i <= 10; ++i)
{
if (!boundary.IsNeighborInXBoundary(i))
{
continue;
}
outData = doSomeConvolution(i, j, k, outdata, inData.Get(i, j, k));
}
}
}
}
};
```
The latter is useful for implementing a convolution that substitutes a constant
value for out-of-bounds indices:
```
struct MyWorklet : public vtkm::worklet::WorkletPointNeighborhood
{
public:
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
using ExecutionSignature = void(_2, Boundary, _3);
template <typename InNeighborhoodT, typename OutDataT>
VTKM_EXEC void operator()(const InNeighborhoodT& inData,
const vtkm::exec::BoundaryState &boundary,
OutDataT& outData) const
{
for (vtkm::IdComponent k = -10; k <= 10; ++k)
{
for (vtkm::IdComponent j = -10; j <= 10; ++j)
{
for (vtkm::IdComponent i = -10; i <= 10; ++i)
{
if (boundary.IsNeighborInBoundary({i, j, k}))
{
outData = doSomeConvolution(i, j, k, outdata, inData.Get(i, j, k));
}
else
{ // substitute zero for out-of-bounds samples:
outData = doSomeConvolution(i, j, k, outdata, 0);
}
}
}
}
}
};
```

@ -0,0 +1,224 @@
# Add ArrayHandleMultiplexer
`vtkm::cont::ArrayHandleMultiplexer` is a fancy `ArrayHandle` that can
mimic being any one of a list of other `ArrayHandle`s. When declared, a set
of a list of `ArrayHandle`s is given to `ArrayHandleMultiplexer`. To use
the `ArrayHandleMultiplexer` it is set to an instance of one of these other
`ArrayHandle`s. Thus, once you compile code to use an
`ArrayHandleMultiplexer`, you can at runtime select any of the types it
supports.
The intention is convert the data from a `vtkm::cont::VariantArrayHandle`
to a `vtkm::cont::ArrayHandleMultiplexer` of some known types. The
`ArrayHandleMultiplexer` can be compiled statically (that is, no virtual
methods are needed). Although the compiler must implement all possible
implementations of the multiplexer, two or more `ArrayHandleMultiplexer`s
can be used together without having to compile every possible combination
of all of them.
## Motivation
`ArrayHandle` is a very flexible templated class that allows us to use the
compiler to adapt our code to pretty much any type of memory layout or
on-line processing. Unfortunately, the template approach requires the code
to know the exact type during compile time.
That is a problem when retrieving data from a
`vtkm::cont::VariantArrayHandle`, which is the case, for example, when
getting data from a `vtkm::cont::DataSet`. The actual type of the array
stored in a `vtkm::cont::VariantArrayHandle` is generally not known at
compile time at the code location where the data is pulled.
Our first approach to this problem was to use metatemplate programming to
iterate over all possible types in the `VariantArrayHandle`. Although this
works, it means that if two or more `VariantArrayHandle`s are dispatched in
a function call, the compiler needs to generate all possible combinations
of the two. This causes long compile times and large executable sizes. It
has lead us to limit the number of types we support, which causes problems
with unsupported arrays.
Our second approach to this problem was to create `ArrayHandleVirtual` to
hide the array type behind a virtual method. This works very well, but is
causing us significant problems on accelerators. Although virtual methods
are supported by CUDA, there are numerous problems that can come up with
the compiled code (such as unknown stack depths or virtual methods
extending across libraries). It is also unknown what problems we will
encounter with other accelerator architectures.
`ArrayHandleMultiplexer` is meant to be a compromise between these two
approaches. Although we are still using metatemplate programming tricks to
iterate over multiple implementations, this compiler looping is localized
to the code to lookup values in the array. This, it is a small amount of
code that needs to be created for each version supported by the
`ArrayHandle`. Also, the code paths can be created independently for each
`ArrayHandleMultiplexer`. Thus, you do not get into the problem of a
combinatorial explosion of types that need to be addressed.
Although `ArrayHandleMultiplexer` still has the problem of being unable to
store a type that is not explicitly listed, the localized expression should
allow us to support many types. By default, we are adding lots of
`ArrayHandleCast`s to the list of supported types. The intention of this is
to allow a filter to specify a value type it operates on and then cast
everything to that type. This further allows us to reduce combination of
types that we have to support.
## Use
The `ArrayHandleMultiplexer` templated class takes a variable number of
template parameters. All the template parameters are expected to be types
of `ArrayHandle`s that the `ArrayHandleMultiplexer` can assume.
For example, let's say we have a use case where we need an array of
indices. Normally, the indices are sequential (0, 1, 2,...), but sometimes
we need to define a custom set of indices. When the indices are sequential,
then an `ArrayHandleIndex` is the best representation. Normally if you also
need to support general arrays you would first have to deep copy the
indices into a physical array. However, with an `ArrayHandleMultiplexer`
you can support both.
``` cpp
vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandleIndex,
vtkm::cont::ArrayHandle<vtkm::Id>> indices;
indices = vtkm::cont::ArrayHandleIndex(ARRAY_SIZE);
```
`indices` can now be used like any other `ArrayHandle`, but for now is
behaving like an `ArrayHandleIndex`. That is, it takes (almost) no actual
space. But if you need to use explicit indices, you can set the `indices`
array to an actual array of indices
``` cpp
vtkm::cont::ArrayHandle<vtkm::Id> indicesInMemory;
// Fill indicesInMemory...
indices = indicesInMemory;
```
All the code that uses `indices` will continue to work.
If `ArrayHandleMultiplexer` is created with only a single template
parameter, then the parameter is interpreted differently. Instead of being
interpreted as a type of array, it is interpreted as the `ValueType` of the
array. In this case, a default set of arrays will set for you. The basic
storage type array will always be part of this list.
``` cpp
vtkm::cont::ArrayHandleMultiplexer<vtkm::FloatDefault> multiplexerArray;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> basicArray;
// Fill basicArray...
multiplexerArray = basicArray;
```
The default list of arrays includes `ArrayHandleCast` from pretty much any
basic type of the same vector length. This allows you to get an
`ArrayHandleMultiplexer` of some known type and then use it for other
types. For example, you can use an integer-based array in a place where you
expect a floating point field.
``` cpp
vtkm::cont::ArrayHandleMultiplexer<vtkm::FloatDefault> multiplexerArray;
vtkm::cont::ArrayHandle<vtkm::Int32> integerField;
// Fill integerField...
multiplexerArray = vtkm::cont::make_ArrayHandleCast<vtkm::FloatDefault>(integerField);
```
We (as developers) also have the option of putting in special storage types
for particular value types. For example, the default list of arrays for a
`Vec<FloatDefault,3>` include `ArrayHandleUniformPointCoordinates` (whereas
this array cannot be placed in other default lists).
``` cpp
vtkm::cont::ArrayHandleMultiplexer<vtkm::Vec<vtkm::FloatDefault, 3>> multiplexerArray;
multiplexerArray = vtkm::cont::ArrayHandleUniformPointCoordinates(vtkm::Id3(50));
```
## Variant
To implement `ArrayHandleMultiplexer`, the class `vtkm::internal::Variant`
was introduced. Although this is an internal class that is not exposed
through the array handle, it is worth documenting its addition as it will
be useful to implement other multiplexing type of objects (such as for
cell sets and locators).
`vtkm::internal::Variant` is a simplified version of C++17's `std::variant`
or boost's `variant`. One of the significant differences between VTK-m's
`Variant` and these other versions is that VTK-m's version does not throw
exceptions on error. Instead, behavior becomes undefined. This is
intentional as not all platforms support exceptions and there could be
consequences on just the possibility for those that do.
Like the aforementioned classes that `vtkm::internal::Variant` is based on,
it behaves much like a `union` of a set of types. Those types are listed as
the `Variant`'s template parameters. The `Variant` can be set to any one of
these types either through construction or assignment. You can also use the
`Emplace` method to construct the object in a `Variant`.
``` cpp
vtkm::internal::Variant<int, float, std::string> variant(5);
// variant is now an int.
variant = 5.0f;
// variant is now a float.
variant.Emplace<std::string>("Hello world");
// variant is now an std::string.
```
The `Variant` maintains the index of which type it is holding. It has
several helpful items to manage the type and index of contained objects:
* `GetIndex()`: A method to retrieve the template parameter index of the
type currently held. In the previous example, the index starts at 0,
becomes 1, then becomes 2.
* `GetIndexOf<T>()`: A static method that returns a `constexpr` of the
index of a given type. In the previous example,
`variant.GetIndexOf<float>()` would return 1.
* `Get<T or I>()`: Given a type, returns the contained object as that
type. Given a number, returns the contained object as a type of the
corresponding index. In the previous example, either `variant.Get<1>()`
or `variant.Get<float>()` would return the `float` value. The behavior
is undefined if the object is not the requested type.
* `IsValid()`: A method that can be used to determine whether the
`Variant` holds an object that can be operated on.
* `Reset()`: A method to remove any contained object and restore to an
invalid state.
Finally, `Variant` contains a `CastAndCall` method. This method takes a
functor followed by a list of optional arguments. The contained object is
cast to the appropriate type and the functor is called with the cast object
followed by the provided arguments. If the functor returns a value, that
value is returned by `CastAndCall`.
`CastAndCall` is an important functionality that makes it easy to wrap
multiplexer objects around a `Variant`. For example, here is how you could
implement executing the `Value` method in an implicit function multiplexer.
``` cpp
class ImplicitFunctionMultiplexer
{
vtkm::internal::Variant<Box, Plane, Sphere> ImplicitFunctionVariant;
// ...
struct ValueFunctor
{
template <typename ImplicitFunctionType>
vtkm::FloatDefault operator()(const ImplicitFunctionType& implicitFunction,
const vtkm::Vec<vtkm::FloatDefault, 3>& point)
{
return implicitFunction.Value(point);
}
};
vtkm::FloatDefault Value(const vtkm::Vec<vtkm::FloatDefault, 3>& point) const
{
return this->ImplicitFunctionVariant.CastAndCall(ValueFunctor{}, point);
}
```

@ -0,0 +1,12 @@
# Enable writing to ArrayHandleCast
Previously, `ArrayHandleCast` was considered a read-only array handle.
However, it is trivial to reverse the cast (now that `ArrayHandleTransform`
supports an inverse transform). So now you can write to a cast array
(assuming the underlying array is writable).
One trivial consequence of this change is that you can no longer make a
cast that cannot be reversed. For example, it was possible to cast a simple
scalar to a `Vec` even though it is not possible to convert a `Vec` to a
scalar value. This was of dubious correctness (it is more of a construction
than a cast) and is easy to recreate with `ArrayHandleTransform`.

@ -23,6 +23,7 @@ if(VTKm_ENABLE_EXAMPLES)
add_subdirectory(histogram)
add_subdirectory(isosurface)
add_subdirectory(lagrangian)
add_subdirectory(mesh_quality)
add_subdirectory(multi_backend)
add_subdirectory(oscillator)
add_subdirectory(particle_advection)

@ -16,6 +16,6 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Clipping Clipping.cxx)
target_link_libraries(Clipping PRIVATE vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(Clipping.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(Clipping
MODIFY_CUDA_FLAGS
DEVICE_SOURCES Clipping.cxx)

@ -16,9 +16,12 @@ find_package(VTKm REQUIRED QUIET)
add_executable(ContourTreeMesh2D ContourTreeMesh2D.cxx)
target_link_libraries(ContourTreeMesh2D vtkm_filter)
vtkm_add_target_information(ContourTreeMesh2D
DEVICE_SOURCES ContourTreeMesh2D.cxx)
add_executable(ContourTreeMesh3D ContourTreeMesh3D.cxx)
target_link_libraries(ContourTreeMesh3D vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(ContourTreeMesh2D.cxx ContourTreeMesh3D.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(ContourTreeMesh3D
MODIFY_CUDA_FLAGS
DEVICE_SOURCES ContourTreeMesh3D.cxx)

@ -56,7 +56,9 @@ find_package(VTKm REQUIRED QUIET)
add_executable(ContourTree ContourTreeApp.cxx)
target_link_libraries(ContourTree vtkm_filter)
vtkm_add_target_information(ContourTree
MODIFY_CUDA_FLAGS
DEVICE_SOURCES ContourTreeApp.cxx)
####################################
# Debug algorithm build
@ -67,7 +69,3 @@ if(TARGET vtkm::tbb)
# TBB 2D/3D/MC
target_compile_definitions(ContourTree PRIVATE ENABLE_SET_NUM_THREADS)
endif()
if(TARGET vtkm::cuda)
set_source_files_properties(ContourTreeApp.cxx PROPERTIES LANGUAGE "CUDA")
endif()

@ -18,6 +18,9 @@ add_executable(CosmoHaloFinder CosmoHaloFinder.cxx)
target_link_libraries(CosmoCenterFinder PRIVATE vtkm_filter)
target_link_libraries(CosmoHaloFinder PRIVATE vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(CosmoCenterFinder.cxx CosmoCenterFinder.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(CosmoCenterFinder
MODIFY_CUDA_FLAGS
DEVICE_SOURCES CosmoCenterFinder.cxx)
vtkm_add_target_information(CosmoHaloFinder
MODIFY_CUDA_FLAGS
DEVICE_SOURCES CosmoHaloFinder.cxx)

@ -13,15 +13,10 @@ project(VTKmDemo CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
set(srcs Demo.cxx)
if(TARGET vtkm_rendering)
if(TARGET vtkm::cuda)
vtkm_compile_as_cuda(cuda_srcs ${srcs})
set(srcs ${cuda_srcs})
endif()
add_executable(Demo ${srcs})
add_executable(Demo Demo.cxx)
target_link_libraries(Demo PRIVATE vtkm_rendering)
vtkm_add_target_information(Demo
MODIFY_CUDA_FLAGS
DEVICE_SOURCES Demo.cxx)
endif()

@ -19,8 +19,8 @@ if(TARGET OpenGL::GL AND
TARGET GLEW::GLEW)
add_executable(GameOfLife GameOfLife.cxx LoadShaders.h)
if(TARGET vtkm::cuda)
set_source_files_properties(GameOfLife.cxx PROPERTIES LANGUAGE "CUDA")
endif()
target_link_libraries(GameOfLife PRIVATE vtkm_filter OpenGL::GL GLEW::GLEW GLUT::GLUT)
vtkm_add_target_information(GameOfLife
MODIFY_CUDA_FLAGS
DEVICE_SOURCES GameOfLife.cxx)
endif()

@ -21,9 +21,9 @@ if(TARGET OpenGL::GL AND
set(gl_libs OpenGL::GL GLEW::GLEW GLUT::GLUT)
add_executable(HelloWorld HelloWorld.cxx LoadShaders.h)
if(TARGET vtkm::cuda)
set_source_files_properties(HelloWorld.cxx PROPERTIES LANGUAGE "CUDA")
endif()
target_link_libraries(HelloWorld PRIVATE vtkm_filter ${gl_libs})
vtkm_add_target_information(HelloWorld
MODIFY_CUDA_FLAGS
DEVICE_SOURCES HelloWorld.cxx)
endif()

@ -15,8 +15,7 @@ find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_MPI)
add_executable(Histogram Histogram.cxx HistogramMPI.h HistogramMPI.hxx)
target_link_libraries(Histogram PRIVATE vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(Histogram.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(Histogram
MODIFY_CUDA_FLAGS
DEVICE_SOURCES Histogram.cxx)
endif()

@ -21,9 +21,8 @@ if(TARGET OpenGL::GL AND
set(gl_libs OpenGL::GL OpenGL::GLU GLEW::GLEW GLUT::GLUT)
add_executable(IsosurfaceUniformGrid IsosurfaceUniformGrid.cxx quaternion.h)
target_link_libraries(IsosurfaceUniformGrid PRIVATE vtkm_filter ${gl_libs})
if(TARGET vtkm::cuda)
set_source_files_properties(IsosurfaceUniformGrid.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(IsosurfaceUniformGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES IsosurfaceUniformGrid.cxx)
endif()

@ -12,9 +12,8 @@ cmake_minimum_required(VERSION 3.8...3.14 FATAL_ERROR)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
if(TARGET vtkm::cuda)
set_source_files_properties(lagrangian.cxx PROPERTIES LANGUAGE "CUDA")
endif()
add_executable(Lagrangian lagrangian.cxx ABCfield.h)
target_link_libraries(Lagrangian PRIVATE vtkm_filter)
vtkm_add_target_information(Lagrangian
MODIFY_CUDA_FLAGS
DEVICE_SOURCES Lagrangian.cxx)

@ -0,0 +1,37 @@
##=============================================================================
##
## Copyright (c) Kitware, Inc.
## All rights reserved.
## See LICENSE.txt for details.
##
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
##
## Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
## Copyright 2015 UT-Battelle, LLC.
## Copyright 2015 Los Alamos National Security.
##
## Under the terms of Contract DE-NA0003525 with NTESS,
## the U.S. Government retains certain rights in this software.
## Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
## Laboratory (LANL), the U.S. Government retains certain rights in
## this software.
##
##=============================================================================
cmake_minimum_required(VERSION 3.8...3.14 FATAL_ERROR)
project(MeshQuality CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
add_executable(MeshQuality MeshQuality.cxx)
target_link_libraries(MeshQuality PRIVATE vtkm_filter)
if(TARGET vtkm::tbb)
target_compile_definitions(MeshQuality PRIVATE BUILDING_TBB_VERSION)
endif()
if(TARGET vtkm::cuda)
set_source_files_properties(MeshQuality.cxx PROPERTIES LANGUAGE "CUDA")
endif()

@ -0,0 +1,286 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2018 UT-Battelle, LLC.
// Copyright 2018 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <string>
#include <vector>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/MeshQuality.h>
#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/io/writer/VTKDataSetWriter.h>
/**
* This example program takes an input VTK unstructured grid file and computes
* the mesh quality of its cells. The mesh quality of a cell type (e.g., tetrahedron,
* hexahedron, triangle) is defined by a metric, which is user-specified.
* The summary statistics of this metric, computed over all cells of its assigned type,
* are written as a new field in the output dataset. There is an output mesh quality
* field for each different cell type that has been assigned a non-empty quality metric
* by the user. Additionally, an ending field is written with the output metric value for
* each cell in the input dataset. The output dataset is named according to the
* user-provided input parameter to this file, or "output.vtk" by default if no parameter
* is provided.
*/
//Adapted from vtkm/cont/testing/MakeTestDataSet.h
//Modified the content of the Make3DExplicitDataSetZoo() function
inline vtkm::cont::DataSet Make3DExplicitDataSet()
{
vtkm::cont::DataSet dataSet;
vtkm::cont::DataSetBuilderExplicit dsb;
using CoordType = vtkm::Vec<vtkm::Float64, 3>;
std::vector<CoordType> coords = {
{ 0.00, 0.00, 0.00 }, { 1.00, 0.00, 0.00 }, { 2.00, 0.00, 0.00 }, { 0.00, 0.00, 1.00 },
{ 1.00, 0.00, 1.00 }, { 2.00, 0.00, 1.00 }, { 0.00, 1.00, 0.00 }, { 1.00, 1.00, 0.00 },
{ 2.00, 1.00, 0.00 }, { 0.00, 1.00, 1.00 }, { 1.00, 1.00, 1.00 }, { 2.00, 1.00, 1.00 },
{ 0.00, 2.00, 0.00 }, { 1.00, 2.00, 0.00 }, { 2.00, 2.00, 0.00 }, { 0.00, 2.00, 1.00 },
{ 1.00, 2.00, 1.00 }, { 2.00, 2.00, 1.00 }, { 1.00, 3.00, 1.00 }, { 2.75, 0.00, 1.00 },
{ 3.00, 0.00, 0.75 }, { 3.00, 0.25, 1.00 }, { 3.00, 1.00, 1.00 }, { 3.00, 1.00, 0.00 },
{ 2.57, 2.00, 1.00 }, { 3.00, 1.75, 1.00 }, { 3.00, 1.75, 0.75 }, { 3.00, 0.00, 0.00 },
{ 2.57, 0.42, 0.57 }, { 2.59, 1.43, 0.71 }
};
std::vector<vtkm::UInt8> shapes;
std::vector<vtkm::IdComponent> numindices;
std::vector<vtkm::Id> conn;
//Construct the shapes/cells of the dataset
//This is a zoo of points, lines, polygons, and polyhedra
shapes.push_back(vtkm::CELL_SHAPE_HEXAHEDRON);
numindices.push_back(8);
conn.push_back(0);
conn.push_back(3);
conn.push_back(4);
conn.push_back(1);
conn.push_back(6);
conn.push_back(9);
conn.push_back(10);
conn.push_back(7);
shapes.push_back(vtkm::CELL_SHAPE_HEXAHEDRON);
numindices.push_back(8);
conn.push_back(1);
conn.push_back(4);
conn.push_back(5);
conn.push_back(2);
conn.push_back(7);
conn.push_back(10);
conn.push_back(11);
conn.push_back(8);
shapes.push_back(vtkm::CELL_SHAPE_TETRA);
numindices.push_back(4);
conn.push_back(24);
conn.push_back(26);
conn.push_back(25);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_TETRA);
numindices.push_back(4);
conn.push_back(8);
conn.push_back(17);
conn.push_back(11);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_PYRAMID);
numindices.push_back(5);
conn.push_back(24);
conn.push_back(17);
conn.push_back(8);
conn.push_back(23);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_PYRAMID);
numindices.push_back(5);
conn.push_back(25);
conn.push_back(22);
conn.push_back(11);
conn.push_back(17);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_WEDGE);
numindices.push_back(6);
conn.push_back(8);
conn.push_back(14);
conn.push_back(17);
conn.push_back(7);
conn.push_back(13);
conn.push_back(16);
shapes.push_back(vtkm::CELL_SHAPE_WEDGE);
numindices.push_back(6);
conn.push_back(11);
conn.push_back(8);
conn.push_back(17);
conn.push_back(10);
conn.push_back(7);
conn.push_back(16);
shapes.push_back(vtkm::CELL_SHAPE_VERTEX);
numindices.push_back(1);
conn.push_back(0);
shapes.push_back(vtkm::CELL_SHAPE_VERTEX);
numindices.push_back(1);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_LINE);
numindices.push_back(2);
conn.push_back(0);
conn.push_back(1);
shapes.push_back(vtkm::CELL_SHAPE_LINE);
numindices.push_back(2);
conn.push_back(11);
conn.push_back(15);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
numindices.push_back(3);
conn.push_back(2);
conn.push_back(4);
conn.push_back(15);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
numindices.push_back(3);
conn.push_back(5);
conn.push_back(6);
conn.push_back(7);
shapes.push_back(vtkm::CELL_SHAPE_QUAD);
numindices.push_back(4);
conn.push_back(0);
conn.push_back(3);
conn.push_back(5);
conn.push_back(2);
shapes.push_back(vtkm::CELL_SHAPE_QUAD);
numindices.push_back(4);
conn.push_back(5);
conn.push_back(4);
conn.push_back(10);
conn.push_back(11);
shapes.push_back(vtkm::CELL_SHAPE_POLYGON);
numindices.push_back(3);
conn.push_back(4);
conn.push_back(7);
conn.push_back(1);
shapes.push_back(vtkm::CELL_SHAPE_POLYGON);
numindices.push_back(4);
conn.push_back(1);
conn.push_back(6);
conn.push_back(7);
conn.push_back(2);
dataSet = dsb.Create(coords, shapes, numindices, conn, "coordinates", "cells");
return dataSet;
}
template <typename T>
int TestMetrics(const char* outFileName, vtkm::cont::DataSet data, T filter)
{
vtkm::cont::DataSet outputData;
try
{
vtkm::io::writer::VTKDataSetWriter writer("testZoo_withPolygons.vtk");
writer.WriteDataSet(data);
outputData = filter.Execute(data);
std::cout << "filter finished\n";
}
catch (vtkm::cont::ErrorExecution&)
{
//TODO: need to add something else here...
std::cerr << "Error occured while executing the filter. Exiting" << std::endl;
return 1;
}
try
{
vtkm::io::writer::VTKDataSetWriter writer(outFileName);
writer.WriteDataSet(outputData);
std::cout << "finished writing data\n";
}
catch (vtkm::io::ErrorIO&)
{
//TODO: need to add something else here...
std::cerr << "Error occured while writing the output data set. Exiting" << std::endl;
return 1;
}
return 0;
}
int main(int argc, char* argv[])
{
//
// Check usage, set filename and read input
//
const char* outFileName = nullptr;
switch (argc)
{
case 1:
std::cerr << "Usage: " << std::endl
<< "$ " << argv[0] << " <input.vtk_file> <output.vtk_fileName>" << std::endl;
return 1;
case 2:
outFileName = "output.vtk";
break;
default:
outFileName = argv[argc - 1];
break;
}
vtkm::cont::DataSet input;
vtkm::io::reader::VTKDataSetReader reader(argv[1]);
//Assign a cell metric to compute for each different
//shape type that may exist in the input dataset. If no metric
//is specified for a shape type, then it is assumed to be EMPTY
//and no metric is computed.
std::vector<vtkm::Pair<vtkm::UInt8, vtkm::filter::CellMetric>> shapeMetrics{
vtkm::make_Pair(vtkm::CELL_SHAPE_LINE, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_TRIANGLE, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_POLYGON, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_TETRA, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_WEDGE, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_QUAD, vtkm::filter::CellMetric::VOLUME),
vtkm::make_Pair(vtkm::CELL_SHAPE_PYRAMID, vtkm::filter::CellMetric::VOLUME)
};
vtkm::filter::MeshQuality filter(shapeMetrics);
try
{
input = reader.ReadDataSet(); //FIELD not supported errors here, but doesnt affect data
//input = Make3DExplicitDataSet();
}
catch (vtkm::io::ErrorIO&)
{
std::cerr << "Error occured while reading input. Exiting" << std::endl;
return 1;
}
TestMetrics(outFileName, input, filter);
return 0;
}

@ -29,9 +29,8 @@ set(srcs
MultiBackend.cxx
)
if(TARGET vtkm::cuda)
set_source_files_properties(${device_srcs} PROPERTIES LANGUAGE "CUDA")
endif()
add_executable(MultiBackend ${device_srcs} ${srcs} ${headers})
target_link_libraries(MultiBackend PRIVATE vtkm_filter Threads::Threads)
vtkm_add_target_information(MultiBackend
MODIFY_CUDA_FLAGS
DEVICE_SOURCES ${device_srcs})

@ -13,9 +13,8 @@ project(Oscillator CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
if (TARGET vtkm::cuda)
set_source_files_properties(Oscillator.cxx PROPERTIES LANGUAGE "CUDA")
endif()
add_executable(Oscillator Oscillator.cxx)
target_link_libraries(Oscillator PRIVATE vtkm_filter)
vtkm_add_target_information(Oscillator
MODIFY_CUDA_FLAGS
DEVICE_SOURCES Oscillator.cxx)

@ -15,11 +15,9 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Particle_Advection ParticleAdvection.cxx)
target_link_libraries(Particle_Advection PRIVATE vtkm_filter)
vtkm_add_target_information(Particle_Advection
MODIFY_CUDA_FLAGS
DEVICE_SOURCES ParticleAdvection.cxx)
if(TARGET vtkm::tbb)
target_compile_definitions(Particle_Advection PRIVATE BUILDING_TBB_VERSION)
endif()
if(TARGET vtkm::cuda)
set_source_files_properties(ParticleAdvection.cxx PROPERTIES LANGUAGE "CUDA")
endif()

@ -14,7 +14,6 @@ project(RedistributePoints CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h)
target_link_libraries(RedistributePoints PRIVATE vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(RedistributePoints.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(RedistributePoints
MODIFY_CUDA_FLAGS
DEVICE_SOURCES RedistributePoints.cxx)

@ -22,9 +22,7 @@ if(TARGET OpenGL::GL AND
add_executable(StreamLineUniformGrid StreamLineUniformGrid.cxx)
target_link_libraries(StreamLineUniformGrid PRIVATE vtkm_filter ${gl_libs})
if(TARGET vtkm::cuda)
set_source_files_properties(StreamLineUniformGrid.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(StreamLineUniformGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES StreamLineUniformGrid.cxx)
endif()

@ -16,9 +16,8 @@ find_package(VTKm REQUIRED QUIET)
if(TARGET vtkm_rendering)
add_executable(Tau_timing TauTiming.cxx)
vtkm_add_target_information(Tau_timing
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TauTiming.cxx)
target_link_libraries(Tau_timing vtkm_cont)
if(TARGET vtkm::cuda)
set_source_files_properties(TauTiming.cxx PROPERTIES LANGUAGE "CUDA")
endif()
endif()

@ -16,8 +16,7 @@ project(TemporalAdvection CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Temporal_Advection TemporalAdvection.cxx)
vtkm_add_target_information(Temporal_Advection
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TemporalAdvection.cxx)
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter)
if(TARGET vtkm::cuda)
set_source_files_properties(TemporalAdvection.cxx PROPERTIES LANGUAGE "CUDA")
endif()

@ -30,11 +30,17 @@ if(TARGET OpenGL::GL AND
target_link_libraries(TetrahedralizeUniformGrid PRIVATE vtkm_filter ${gl_libs})
target_link_libraries(TriangulateUniformGrid PRIVATE vtkm_filter ${gl_libs})
if(TARGET vtkm::cuda)
set_source_files_properties(TetrahedralizeExplicitGrid.cxx
TriangulateExplicitGrid.cxx
TetrahedralizeUniformGrid.cxx
TriangulateUniformGrid.cxx PROPERTIES LANGUAGE "CUDA")
endif()
vtkm_add_target_information(TetrahedralizeExplicitGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TetrahedralizeExplicitGrid.cxx)
vtkm_add_target_information(TriangulateExplicitGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TriangulateExplicitGrid.cxx)
vtkm_add_target_information(TetrahedralizeUniformGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TetrahedralizeUniformGrid.cxx)
vtkm_add_target_information(TriangulateUniformGrid
MODIFY_CUDA_FLAGS
DEVICE_SOURCES TriangulateUniformGrid.cxx)
endif()

@ -16,5 +16,6 @@ find_package(VTKm REQUIRED QUIET)
if(TARGET vtkm::cuda)
add_executable(UnifiedMemory_CUDA UnifiedMemory.cu)
target_link_libraries(UnifiedMemory_CUDA PRIVATE vtkm_filter)
vtkm_add_target_information(UnifiedMemory_CUDA MODIFY_CUDA_FLAGS)
endif()

@ -40,6 +40,52 @@ struct ListTagCheck : std::is_base_of<vtkm::detail::ListRoot, ListTag>
VTKM_STATIC_ASSERT_MSG((::vtkm::internal::ListTagCheck<tag>::value), \
"Provided type is not a valid VTK-m list tag.")
namespace internal
{
namespace detail
{
template <typename ListTag>
struct ListTagAsBrigandListImpl
{
VTKM_IS_LIST_TAG(ListTag);
using type = typename ListTag::list;
};
} // namespace detail
/// Converts a ListTag to a brigand::list.
///
template <typename ListTag>
using ListTagAsBrigandList = typename detail::ListTagAsBrigandListImpl<ListTag>::type;
} // namespace internal
namespace detail
{
template <typename BrigandList, template <typename...> class Target>
struct ListTagApplyImpl;
template <typename... Ts, template <typename...> class Target>
struct ListTagApplyImpl<brigand::list<Ts...>, Target>
{
using type = Target<Ts...>;
};
} // 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 ListTag, template <typename...> class Target>
using ListTagApply =
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.
@ -60,7 +106,10 @@ struct ListTagEmpty : detail::ListRoot
template <typename ListTag1, typename ListTag2>
struct ListTagJoin : detail::ListRoot
{
using list = typename detail::ListJoin<typename ListTag1::list, typename ListTag2::list>::type;
VTKM_IS_LIST_TAG(ListTag1);
VTKM_IS_LIST_TAG(ListTag2);
using list = typename detail::ListJoin<internal::ListTagAsBrigandList<ListTag1>,
internal::ListTagAsBrigandList<ListTag2>>::type;
};
@ -68,7 +117,9 @@ struct ListTagJoin : detail::ListRoot
template <typename ListTag, typename Type>
struct ListTagAppend : detail::ListRoot
{
using list = typename detail::ListJoin<typename ListTag::list, detail::ListBase<Type>>::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.
@ -76,7 +127,9 @@ struct ListTagAppend : detail::ListRoot
template <typename ListTag, typename Type>
struct ListTagAppendUnique : detail::ListRoot
{
using list = typename detail::ListAppendUniqueImpl<typename ListTag::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
@ -84,8 +137,32 @@ struct ListTagAppendUnique : detail::ListRoot
template <typename ListTag1, typename ListTag2>
struct ListTagIntersect : detail::ListRoot
{
using list =
typename detail::ListIntersect<typename ListTag1::list, typename ListTag2::list>::type;
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
{
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.
///
/// There is a static member named \c value that is set to the length of the list.
///
template <typename ListTag>
struct ListSize
{
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
@ -95,21 +172,26 @@ template <typename Functor, typename ListTag, typename... Args>
VTKM_CONT void ListForEach(Functor&& f, ListTag, Args&&... args)
{
VTKM_IS_LIST_TAG(ListTag);
detail::ListForEachImpl(
std::forward<Functor>(f), typename ListTag::list{}, std::forward<Args>(args)...);
detail::ListForEachImpl(std::forward<Functor>(f),
internal::ListTagAsBrigandList<ListTag>{},
std::forward<Args>(args)...);
}
/// Generate a tag that is the cross product of two other tags. The resulting
// a tag has the form of Tag< brigand::list<A1,B1>, brigand::list<A1,B2> .... >
/// tag has the form of Tag< brigand::list<A1,B1>, brigand::list<A1,B2> .... >
///
template <typename ListTag1, typename ListTag2>
struct ListCrossProduct : detail::ListRoot
{
VTKM_IS_LIST_TAG(ListTag1);
VTKM_IS_LIST_TAG(ListTag2);
using list =
typename detail::ListCrossProductImpl<typename ListTag1::list, typename ListTag2::list>::type;
typename detail::ListCrossProductImpl<internal::ListTagAsBrigandList<ListTag1>,
internal::ListTagAsBrigandList<ListTag2>>::type;
};
/// Checks to see if the given \c Type is in the list pointed to by \c ListTag.
/// \brief Checks to see if the given \c Type is in the list pointed to by \c ListTag.
///
/// There is a static boolean named \c value that is set to true if the type is
/// contained in the list and false otherwise.
///
@ -117,7 +199,33 @@ template <typename ListTag, typename Type>
struct ListContains
{
VTKM_IS_LIST_TAG(ListTag);
static constexpr bool value = detail::ListContainsImpl<Type, typename ListTag::list>::value;
static constexpr bool value =
detail::ListContainsImpl<Type, internal::ListTagAsBrigandList<ListTag>>::value;
};
/// \brief Finds the type at the given index.
///
/// This struct contains subtype \c type that resolves to the type at the given index.
///
template <typename ListTag, vtkm::IdComponent Index>
struct ListTypeAt
{
VTKM_IS_LIST_TAG(ListTag);
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

@ -82,19 +82,21 @@ struct IsInValidArrayHandle
/// Both of these have a typedef named value with the respective boolean value.
///
template <typename ArrayHandle>
struct IsWriteableArrayHandle
struct IsWritableArrayHandle
{
private:
using ValueType = typename ArrayHandle::PortalControl::ValueType;
template <typename U,
typename S = decltype(std::declval<U>().Set(vtkm::Id{},
std::declval<typename U::ValueType>()))>
static std::true_type hasSet(int);
template <typename U>
static std::false_type hasSet(...);
//All ArrayHandles that use ImplicitStorage as the final writable location
//will have a value type of void*, which is what we are trying to detect
using RawValueType = typename std::remove_pointer<ValueType>::type;
using IsVoidType = std::is_void<RawValueType>;
using PortalType = typename ArrayHandle::PortalControl;
public:
using type = std::integral_constant<bool, !IsVoidType::value>;
static constexpr bool value = !IsVoidType::value;
using type = decltype(hasSet<PortalType>(0));
static constexpr bool value = type::value;
};
/// Checks to see if the given object is an array handle. This check is

@ -45,14 +45,16 @@ 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<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleCast,
(ArrayHandleCast<T, ArrayHandleType>),
(vtkm::cont::ArrayHandleTransform<ArrayHandleType,
internal::Cast<typename ArrayHandleType::ValueType, T>>));
internal::Cast<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>));
ArrayHandleCast(const ArrayHandleType& handle)
: Superclass(handle)
@ -172,7 +174,9 @@ struct SerializableTypeString<vtkm::cont::internal::Cast<T1, T2>>
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::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
{
};
}
@ -192,7 +196,9 @@ struct Serialization<vtkm::cont::internal::Cast<T1, T2>>
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::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
{
};

@ -0,0 +1,631 @@
//============================================================================
// 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_cont_ArrayHandleMultiplexer_h
#define vtk_m_cont_ArrayHandleMultiplexer_h
#include <vtkm/TypeListTag.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/internal/Variant.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/StorageListTag.h>
namespace vtkm
{
namespace internal
{
namespace detail
{
struct ArrayPortalMultiplexerGetNumberOfValuesFunctor
{
template <typename PortalType>
VTKM_EXEC_CONT vtkm::Id operator()(const PortalType& portal) const noexcept
{
return portal.GetNumberOfValues();
}
};
struct ArrayPortalMultiplexerGetFunctor
{
template <typename PortalType>
VTKM_EXEC_CONT typename PortalType::ValueType operator()(const PortalType& portal,
vtkm::Id index) const noexcept
{
return portal.Get(index);
}
};
struct ArrayPortalMultiplexerSetFunctor
{
template <typename PortalType>
VTKM_EXEC_CONT void operator()(const PortalType& portal,
vtkm::Id index,
const typename PortalType::ValueType& value) const noexcept
{
portal.Set(index, value);
}
};
} // namespace detail
template <typename... PortalTypes>
struct ArrayPortalMultiplexer
{
using PortalVariantType = vtkm::internal::Variant<PortalTypes...>;
PortalVariantType PortalVariant;
using ValueType = typename PortalVariantType::template TypeAt<0>::ValueType;
ArrayPortalMultiplexer() = default;
~ArrayPortalMultiplexer() = default;
ArrayPortalMultiplexer(ArrayPortalMultiplexer&&) = default;
ArrayPortalMultiplexer(const ArrayPortalMultiplexer&) = default;
ArrayPortalMultiplexer& operator=(ArrayPortalMultiplexer&&) = default;
ArrayPortalMultiplexer& operator=(const ArrayPortalMultiplexer&) = default;
template <typename Portal>
VTKM_EXEC_CONT ArrayPortalMultiplexer(const Portal& src) noexcept : PortalVariant(src)
{
}
template <typename Portal>
VTKM_EXEC_CONT ArrayPortalMultiplexer& operator=(const Portal& src) noexcept
{
this->PortalVariant = src;
return *this;
}
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const noexcept
{
return this->PortalVariant.CastAndCall(
detail::ArrayPortalMultiplexerGetNumberOfValuesFunctor{});
}
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const noexcept
{
return this->PortalVariant.CastAndCall(detail::ArrayPortalMultiplexerGetFunctor{}, index);
}
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const noexcept
{
this->PortalVariant.CastAndCall(detail::ArrayPortalMultiplexerSetFunctor{}, index, value);
}
};
} // namespace internal
namespace cont
{
template <typename... StorageTags>
struct StorageTagMultiplexer
{
};
namespace internal
{
namespace detail
{
struct MultiplexerGetNumberOfValuesFunctor
{
template <typename ArrayHandleType>
VTKM_CONT vtkm::Id operator()(ArrayHandleType&& array) const
{
return array.GetNumberOfValues();
}
};
struct MultiplexerAllocateFunctor
{
template <typename ArrayHandleType>
VTKM_CONT void operator()(ArrayHandleType&& array, vtkm::Id numberOfValues) const
{
array.Allocate(numberOfValues);
}
};
struct MultiplexerShrinkFunctor
{
template <typename ArrayHandleType>
VTKM_CONT void operator()(ArrayHandleType&& array, vtkm::Id numberOfValues) const
{
array.Shrink(numberOfValues);
}
};
struct MultiplexerReleaseResourcesFunctor
{
template <typename ArrayHandleType>
VTKM_CONT vtkm::Id operator()(ArrayHandleType&& array) const
{
return array.ReleaseResources();
}
};
struct MultiplexerReleaseResourcesExecutionFunctor
{
template <typename ArrayHandleType>
VTKM_CONT void operator()(ArrayHandleType&& array) const
{
array.ReleaseResourcesExecution();
}
};
} // namespace detail
template <typename ValueType_, typename... StorageTags>
class Storage<ValueType_, StorageTagMultiplexer<StorageTags...>>
{
public:
using ValueType = ValueType_;
private:
template <typename S>
using StorageToArrayHandle = vtkm::cont::ArrayHandle<ValueType, S>;
template <typename S>
using StorageToPortalControl = typename StorageToArrayHandle<S>::PortalControl;
template <typename S>
using StorageToPortalConstControl = typename StorageToArrayHandle<S>::PortalConstControl;
using ArrayHandleVariantType = vtkm::internal::Variant<StorageToArrayHandle<StorageTags>...>;
ArrayHandleVariantType ArrayHandleVariant;
public:
using PortalType = vtkm::internal::ArrayPortalMultiplexer<StorageToPortalControl<StorageTags>...>;
using PortalConstType =
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalConstControl<StorageTags>...>;
Storage() = default;
Storage(Storage&&) = default;
Storage(const Storage&) = default;
Storage& operator=(Storage&&) = default;
Storage& operator=(const Storage&) = default;
template <typename S>
VTKM_CONT Storage(vtkm::cont::ArrayHandle<ValueType, S>&& rhs)
: ArrayHandleVariant(std::move(rhs))
{
}
template <typename S>
VTKM_CONT Storage(const vtkm::cont::ArrayHandle<ValueType, S>& src)
: ArrayHandleVariant(src)
{
}
private:
struct GetPortalFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalType operator()(ArrayHandleType&& array) const
{
return PortalType(array.GetPortalControl());
}
};
struct GetPortalConstFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalConstType operator()(ArrayHandleType&& array) const
{
return PortalConstType(array.GetPortalConstControl());
}
};
public:
VTKM_CONT PortalType GetPortal()
{
return this->ArrayHandleVariant.CastAndCall(GetPortalFunctor{});
}
VTKM_CONT PortalConstType GetPortalConst() const
{
return this->ArrayHandleVariant.CastAndCall(GetPortalConstFunctor{});
}
VTKM_CONT vtkm::Id GetNumberOfValues() const
{
return this->ArrayHandleVariant.CastAndCall(detail::MultiplexerGetNumberOfValuesFunctor{});
}
VTKM_CONT void Allocate(vtkm::Id numberOfValues)
{
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerAllocateFunctor{}, numberOfValues);
}
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
{
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerShrinkFunctor{}, numberOfValues);
}
VTKM_CONT void ReleaseResources()
{
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerReleaseResourcesFunctor{});
}
VTKM_CONT ArrayHandleVariantType& GetArrayHandleVariant() { return this->ArrayHandleVariant; }
};
template <typename ValueType_, typename... StorageTags, typename Device>
class ArrayTransfer<ValueType_, StorageTagMultiplexer<StorageTags...>, Device>
{
public:
using ValueType = ValueType_;
private:
using StorageTag = StorageTagMultiplexer<StorageTags...>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
template <typename S>
using StorageToArrayHandle = vtkm::cont::ArrayHandle<ValueType, S>;
template <typename S>
using StorageToPortalExecution =
typename StorageToArrayHandle<S>::template ExecutionTypes<Device>::Portal;
template <typename S>
using StorageToPortalConstExecution =
typename StorageToArrayHandle<S>::template ExecutionTypes<Device>::PortalConst;
public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
using PortalExecution =
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalExecution<StorageTags>...>;
using PortalConstExecution =
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalConstExecution<StorageTags>...>;
private:
StorageType* StoragePointer;
public:
VTKM_CONT ArrayTransfer(StorageType* storage)
: StoragePointer(storage)
{
}
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->StoragePointer->GetNumberOfValues(); }
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInputFunctor{});
}
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInPlaceFunctor{});
}
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
{
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForOutputFunctor{},
numberOfValues);
}
VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
{
// Implementation of this method should be unnecessary. The internal
// array handles should automatically retrieve the output data as
// necessary.
}
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
{
this->StoragePointer->GetArrayHandleVariant().CastAndCall(detail::MultiplexerShrinkFunctor{},
numberOfValues);
}
VTKM_CONT void ReleaseResources()
{
this->StoragePointer->GetArrayHandleVariant().CastAndCall(
detail::MultiplexerReleaseResourcesExecutionFunctor{});
}
private:
struct PrepareForInputFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalConstExecution operator()(const ArrayHandleType& array)
{
return PortalConstExecution(array.PrepareForInput(Device{}));
}
};
struct PrepareForInPlaceFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalExecution operator()(ArrayHandleType& array)
{
return PortalExecution(array.PrepareForInPlace(Device{}));
}
};
struct PrepareForOutputFunctor
{
template <typename ArrayHandleType>
VTKM_CONT PortalExecution operator()(ArrayHandleType& array, vtkm::Id numberOfValues)
{
return PortalExecution(array.PrepareForOutput(numberOfValues, Device{}));
}
};
};
} // namespace internal
namespace detail
{
template <typename ValueType, typename... ArrayHandleTypes>
struct ArrayHandleMultiplexerTraits
{
// If there is a compile error in this group of lines, then the list tag given to
// ArrayHandleMultiplexer must contain an invalid ArrayHandle. That could mean that
// it is not an ArrayHandle type or it could mean that the value type does not match
// the appropriate value type.
template <typename ArrayHandle>
struct CheckArrayHandleTransform
{
VTKM_IS_ARRAY_HANDLE(ArrayHandle);
VTKM_STATIC_ASSERT((std::is_same<ValueType, typename ArrayHandle::ValueType>::value));
};
using CheckArrayHandle = brigand::list<CheckArrayHandleTransform<ArrayHandleTypes>...>;
// Note that this group of code could be simplified as the pair of lines:
// template <typename ArrayHandle>
// using ArrayHandleToStorageTag = typename ArrayHandle::StorageTag;
// However, there are issues with older Visual Studio compilers that is not working
// correctly with that form.
template <typename ArrayHandle>
struct ArrayHandleToStorageTagImpl
{
using Type = typename ArrayHandle::StorageTag;
};
template <typename ArrayHandle>
using ArrayHandleToStorageTag = typename ArrayHandleToStorageTagImpl<ArrayHandle>::Type;
using StorageTag =
vtkm::cont::StorageTagMultiplexer<ArrayHandleToStorageTag<ArrayHandleTypes>...>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
};
}
/// \brief Base implementation of \c ArrayHandleMultiplexer.
///
/// This behavies the same as \c ArrayHandleMultiplexer, but the template parameters are
/// more explicit. The first template parameter must be the \c ValueType of the array.
/// The remaining template parameters are the array handles to support.
///
template <typename ValueType_, typename... ArrayHandleTypes>
class ArrayHandleMultiplexerBase
: public vtkm::cont::ArrayHandle<
ValueType_,
typename detail::ArrayHandleMultiplexerTraits<ValueType_, ArrayHandleTypes...>::StorageTag>
{
using Traits = detail::ArrayHandleMultiplexerTraits<ValueType_, ArrayHandleTypes...>;
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleMultiplexerBase,
(ArrayHandleMultiplexerBase<ValueType_, ArrayHandleTypes...>),
(vtkm::cont::ArrayHandle<ValueType_, typename Traits::StorageTag>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
template <typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexerBase(
const vtkm::cont::ArrayHandle<ValueType, RealStorageTag>& src)
: Superclass(StorageType(src))
{
}
template <typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexerBase(vtkm::cont::ArrayHandle<ValueType, RealStorageTag>&& rhs)
: Superclass(StorageType(std::move(rhs)))
{
}
};
namespace internal
{
namespace detail
{
template <typename ValueType>
struct MakeArrayListFromStorage
{
template <typename S>
using Transform = vtkm::cont::ArrayHandle<ValueType, S>;
};
template <typename ValueType>
struct SupportedArrays
: vtkm::ListTagTransform<vtkm::cont::StorageListTagSupported,
MakeArrayListFromStorage<ValueType>::template Transform>
{
};
template <typename DestType, typename SrcTypeList>
struct MakeCastArrayListImpl
{
using TypeStoragePairs = vtkm::ListCrossProduct<SrcTypeList, vtkm::cont::StorageListTagSupported>;
template <typename Pair>
struct PairToCastArrayImpl;
template <typename T, typename S>
struct PairToCastArrayImpl<brigand::list<T, S>>
{
using Type = vtkm::cont::ArrayHandleCast<DestType, vtkm::cont::ArrayHandle<T, S>>;
};
template <typename Pair>
using PairToCastArray = typename PairToCastArrayImpl<Pair>::Type;
using Type = vtkm::ListTagTransform<TypeStoragePairs, PairToCastArray>;
};
template <typename DestType>
struct MakeCastArrayList
{
using Type = typename MakeCastArrayListImpl<DestType, vtkm::TypeListTagScalarAll>::Type;
};
template <typename ComponentType, vtkm::IdComponent N>
struct MakeCastArrayList<vtkm::Vec<ComponentType, N>>
{
template <typename T>
using ScalarToVec = vtkm::Vec<T, N>;
using SourceTypes = vtkm::ListTagTransform<vtkm::TypeListTagScalarAll, ScalarToVec>;
using Type = typename MakeCastArrayListImpl<vtkm::Vec<ComponentType, N>, SourceTypes>::Type;
};
template <typename T>
struct ArrayHandleMultiplexerDefaultArraysBase
: vtkm::ListTagJoin<SupportedArrays<T>, typename MakeCastArrayList<T>::Type>
{
};
} // namespace detail
template <typename T>
struct ArrayHandleMultiplexerDefaultArrays : detail::ArrayHandleMultiplexerDefaultArraysBase<T>
{
};
template <>
struct ArrayHandleMultiplexerDefaultArrays<vtkm::Vec<vtkm::FloatDefault, 3>>
: vtkm::ListTagJoin<
detail::ArrayHandleMultiplexerDefaultArraysBase<vtkm::Vec<vtkm::FloatDefault, 3>>,
vtkm::ListTagBase<
#if 1
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>,
#endif
vtkm::cont::ArrayHandleUniformPointCoordinates>>
{
};
} // namespace internal
namespace detail
{
template <typename ValueType, typename ListTagArrays>
struct ArrayHandleMultiplexerChooseBaseImpl
{
VTKM_IS_LIST_TAG(ListTagArrays);
template <typename BrigandListArrays>
struct BrigandListArraysToArrayHandleMultiplexerBase;
template <typename... ArrayHandleTypes>
struct BrigandListArraysToArrayHandleMultiplexerBase<brigand::list<ArrayHandleTypes...>>
{
using Type = vtkm::cont::ArrayHandleMultiplexerBase<ValueType, ArrayHandleTypes...>;
};
using Type = typename BrigandListArraysToArrayHandleMultiplexerBase<
vtkm::internal::ListTagAsBrigandList<ListTagArrays>>::Type;
};
template <typename ValueType>
using ArrayHandleMultiplexerChooseBase = typename ArrayHandleMultiplexerChooseBaseImpl<
ValueType,
internal::ArrayHandleMultiplexerDefaultArrays<ValueType>>::Type;
} // namespace detail
/// \brief An ArrayHandle that can behave like several other handles.
///
/// An \c ArrayHandleMultiplexer simply redirects its calls to another \c ArrayHandle. However
/// the type of that \c ArrayHandle does not need to be (completely) known at runtime. Rather,
/// \c ArrayHandleMultiplexer is defined over a set of possible \c ArrayHandle types. Any
/// one of these \c ArrayHandles may be assigned to the \c ArrayHandleMultiplexer.
///
/// When a value is retreived from the \c ArrayHandleMultiplexer, the multiplexer checks to
/// see which type of array is currently stored in it. It then redirects to the \c ArrayHandle
/// of the appropriate type.
///
/// If only one template parameter is given, it is assumed to be the \c ValueType of the
/// array. A default list of supported arrays is supported (see
/// \c vtkm::cont::internal::ArrayHandleMultiplexerDefaultArrays.) If multiple template
/// parameters are given, they are all considered possible \c ArrayHandle types.
///
template <typename... Ts>
class ArrayHandleMultiplexer;
template <typename ValueType_>
class ArrayHandleMultiplexer<ValueType_>
: public detail::ArrayHandleMultiplexerChooseBase<ValueType_>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleMultiplexer,
(ArrayHandleMultiplexer<ValueType_>),
(detail::ArrayHandleMultiplexerChooseBase<ValueType_>));
template <typename RealT, typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexer(const vtkm::cont::ArrayHandle<RealT, RealStorageTag>& src)
: Superclass(src)
{
}
template <typename RealT, typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexer(vtkm::cont::ArrayHandle<RealT, RealStorageTag>&& rhs)
: Superclass(std::move(rhs))
{
}
};
template <typename ArrayType0, typename... ArrayTypes>
class ArrayHandleMultiplexer<ArrayType0, ArrayTypes...>
: public vtkm::cont::ArrayHandleMultiplexerBase<typename ArrayType0::ValueType,
ArrayType0,
ArrayTypes...>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleMultiplexer,
(ArrayHandleMultiplexer<ArrayType0, ArrayTypes...>),
(vtkm::cont::ArrayHandleMultiplexerBase<typename ArrayType0::ValueType,
ArrayType0,
ArrayTypes...>));
template <typename RealT, typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexer(const vtkm::cont::ArrayHandle<RealT, RealStorageTag>& src)
: Superclass(src)
{
}
template <typename RealT, typename RealStorageTag>
VTKM_CONT ArrayHandleMultiplexer(vtkm::cont::ArrayHandle<RealT, RealStorageTag>&& rhs)
: Superclass(std::move(rhs))
{
}
};
} // namespace cont
} // namespace vtkm
#endif //vtk_m_cont_ArrayHandleMultiplexer_h

@ -16,6 +16,8 @@
#include <vtkm/cont/ExecutionAndControlObjectBase.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
#include <vtkm/cont/serial/internal/DeviceAdapterRuntimeDetectorSerial.h>
namespace vtkm
@ -148,7 +150,8 @@ public:
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
{
return this->Portal.Set(index, this->InverseFunctor(value));
using call_supported_t = typename vtkm::internal::PortalSupportsSets<PortalType>::type;
this->Set(call_supported_t(), index, value);
}
VTKM_SUPPRESS_EXEC_WARNINGS
@ -157,6 +160,14 @@ public:
private:
InverseFunctorType InverseFunctor;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
inline void Set(std::true_type, vtkm::Id index, const ValueType& value) const
{
this->Portal.Set(index, this->InverseFunctor(value));
}
VTKM_EXEC_CONT inline void Set(std::false_type, vtkm::Id, const ValueType&) const {}
};
}
}
@ -274,19 +285,16 @@ class Storage<typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueT
public:
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
// This is meant to be invalid. Because Transform arrays are read only, you
// should only be able to use the const version.
struct PortalType
{
using ValueType = void*;
using IteratorType = void*;
};
using PortalConstType =
vtkm::exec::internal::ArrayPortalTransform<ValueType,
typename ArrayHandleType::PortalConstControl,
typename FunctorManager::FunctorType>;
// Note that this array is read only, so you really should only be getting the const
// version of the portal. If you actually try to write to this portal, you will
// get an error.
using PortalType = PortalConstType;
VTKM_CONT
Storage()
: Valid(false)

@ -27,6 +27,7 @@ set(headers
ArrayHandleGroupVecVariable.h
ArrayHandleImplicit.h
ArrayHandleIndex.h
ArrayHandleMultiplexer.h
ArrayHandlePermutation.h
ArrayHandleReverse.h
ArrayHandleStreaming.h
@ -183,7 +184,7 @@ vtkm_library( NAME vtkm_cont
SOURCES ${sources}
TEMPLATE_SOURCES ${template_sources}
HEADERS ${headers}
WRAP_FOR_CUDA ${device_sources}
DEVICE_SOURCES ${device_sources}
)
add_subdirectory(internal)

@ -48,6 +48,8 @@ public:
VTKM_EXEC void operator()(const CoordVecType& coord, IdType& label) const
{
vtkm::Vec<vtkm::Id, 3> ijk = (coord - Min) / Dxdydz;
ijk = vtkm::Max(ijk, vtkm::Id3(0));
ijk = vtkm::Min(ijk, this->Dims - vtkm::Id3(1));
label = ijk[0] + ijk[1] * Dims[0] + ijk[2] * Dims[0] * Dims[1];
}

@ -12,6 +12,8 @@
#include <vtkm/internal/IndicesExtrude.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
@ -97,17 +99,14 @@ class VTKM_ALWAYS_EXPORT Storage<T, internal::StorageTagExtrudePlane>
public:
using ValueType = T;
// This is meant to be invalid. Because point arrays are read only, you
// should only be able to use the const version.
struct PortalType
{
using ValueType = void*;
using IteratorType = void*;
};
using PortalConstType =
vtkm::exec::ArrayPortalExtrudePlane<typename HandleType::PortalConstControl>;
// Note that this array is read only, so you really should only be getting the const
// version of the portal. If you actually try to write to this portal, you will
// get an error.
using PortalType = PortalConstType;
Storage()
: Array()
, NumberOfPlanes(0)
@ -120,7 +119,11 @@ public:
{
}
PortalType GetPortal() { return PortalType{}; }
PortalType GetPortal()
{
throw vtkm::cont::ErrorBadType(
"Extrude ArrayHandles are read only. Cannot get writable portal.");
}
PortalConstType GetPortalConst() const
{
@ -382,16 +385,13 @@ class Storage<T, internal::StorageTagExtrude>
public:
using ValueType = T;
// This is meant to be invalid. Because point arrays are read only, you
// should only be able to use the const version.
struct PortalType
{
using ValueType = void*;
using IteratorType = void*;
};
using PortalConstType = exec::ArrayPortalExtrude<TPortalType>;
// Note that this array is read only, so you really should only be getting the const
// version of the portal. If you actually try to write to this portal, you will
// get an error.
using PortalType = PortalConstType;
Storage()
: Array()
, NumberOfPlanes(0)
@ -415,7 +415,11 @@ public:
VTKM_ASSERT(this->Array.GetNumberOfValues() >= 0);
}
PortalType GetPortal() { return PortalType{}; }
PortalType GetPortal()
{
throw vtkm::cont::ErrorBadType(
"Extrude ArrayHandles are read only. Cannot get writable portal.");
}
PortalConstType GetPortalConst() const
{

@ -53,13 +53,9 @@ public:
using ValueType = typename ArrayPortalType::ValueType;
using PortalConstType = ArrayPortalType;
// This is meant to be invalid. Because implicit arrays are read only, you
// should only be able to use the const version.
struct PortalType
{
using ValueType = void*;
using IteratorType = void*;
};
// Note that this portal is likely to be read-only, so you will probably get an error
// if you try to write to it.
using PortalType = ArrayPortalType;
VTKM_CONT
Storage(const PortalConstType& portal = PortalConstType())

@ -27,6 +27,12 @@ namespace cont
struct VTKM_ALWAYS_EXPORT StorageListTagBasic : vtkm::ListTagBase<vtkm::cont::StorageTagBasic>
{
};
// If we want to compile VTK-m with support of memory layouts other than the basic layout, then
// add the appropriate storage tags here.
struct VTKM_ALWAYS_EXPORT StorageListTagSupported : vtkm::ListTagBase<vtkm::cont::StorageTagBasic>
{
};
}
} // namespace vtkm::cont

@ -206,9 +206,9 @@ void StorageVirtualImpl<T, S>::ControlPortalForOutput(
vtkm::cont::internal::TransferInfoArray& payload)
{
using HT = vtkm::cont::ArrayHandle<T, S>;
constexpr auto isWriteable = typename vtkm::cont::internal::IsWriteableArrayHandle<HT>::type{};
constexpr auto isWritable = typename vtkm::cont::internal::IsWritableArrayHandle<HT>::type{};
detail::make_writableHostPortal(isWriteable, payload, this->Handle);
detail::make_writableHostPortal(isWritable, payload, this->Handle);
}
template <typename T, typename S>

@ -22,7 +22,7 @@ struct RemoveDisabledDevice
};
/// TMP code to generate enabled device timer container
using AllDeviceList = vtkm::cont::DeviceAdapterListTagCommon::list;
using AllDeviceList = vtkm::internal::ListTagAsBrigandList<vtkm::cont::DeviceAdapterListTagCommon>;
using EnabledDeviceList = brigand::fold<AllDeviceList,
brigand::list<>,
RemoveDisabledDevice<brigand::_state, brigand::_element>>;

@ -373,8 +373,9 @@ template <typename TypeList, typename StorageList>
struct ListTagDynamicTypes : vtkm::detail::ListRoot
{
using crossProduct = typename vtkm::ListCrossProduct<TypeList, StorageList>;
// using list = typename crossProduct::list;
using list = ::brigand::remove_if<typename crossProduct::list, IsUndefinedStorage<brigand::_1>>;
// using list = vtkm::internal::ListTagAsBrigandList<crossProduct>;
using list = ::brigand::remove_if<vtkm::internal::ListTagAsBrigandList<crossProduct>,
IsUndefinedStorage<brigand::_1>>;
};

@ -11,6 +11,7 @@
set(unit_tests
UnitTestCudaArrayHandle.cu
UnitTestCudaArrayHandleFancy.cu
UnitTestCudaArrayHandleMultiplexer.cu
UnitTestCudaArrayHandleVirtualCoordinates.cu
UnitTestCudaBitField.cu
UnitTestCudaCellLocatorRectilinearGrid.cu

@ -0,0 +1,20 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/testing/TestingArrayHandleMultiplexer.h>
int UnitTestCudaArrayHandleMultiplexer(int argc, char* argv[])
{
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagCuda{});
return vtkm::cont::testing::TestingArrayHandleMultiplexer<vtkm::cont::DeviceAdapterTagCuda>::Run(
argc, argv);
}

@ -60,8 +60,8 @@ void buildIndexOffsets(const ArrayHandleIndices& numIndices,
ArrayHandleOffsets offsets,
vtkm::cont::DeviceAdapterId deviceId)
{
using IsWriteable = vtkm::cont::internal::IsWriteableArrayHandle<ArrayHandleOffsets>;
buildIndexOffsets(numIndices, offsets, deviceId, typename IsWriteable::type());
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<ArrayHandleOffsets>;
buildIndexOffsets(numIndices, offsets, deviceId, typename IsWritable::type());
}
template <typename ShapeStorageTag = VTKM_DEFAULT_STORAGE_TAG,

@ -36,6 +36,18 @@
#define VTKM_OPENMP_DIRECTIVE(directive)
#endif // _OPENMP
// See "OpenMP data sharing" section of
// https://www.gnu.org/software/gcc/gcc-9/porting_to.html. OpenMP broke
// backwards compatibility regarding const variable handling.
// tl;dr, put all const variables accessed from openmp blocks in a
// VTKM_OPENMP_SHARED_CONST(var1, var2, ...) macro. This will do The Right Thing
// on all gcc.
#if defined(__GNUC__) && __GNUC__ >= 9
#define VTKM_OPENMP_SHARED_CONST(...) shared(__VA_ARGS__)
#else
#define VTKM_OPENMP_SHARED_CONST(...)
#endif
// When defined, supported type / operator combinations will use the OpenMP
// reduction(...) clause. Otherwise, all reductions use the general
// implementation with a manual reduction once the threads complete.
@ -266,6 +278,23 @@ using OpenMPReductionSupported = std::false_type;
struct ReduceHelper
{
// std::is_integral, but adapted to see through vecs and pairs.
template <typename T>
struct IsIntegral : public std::is_integral<T>
{
};
template <typename T, vtkm::IdComponent Size>
struct IsIntegral<vtkm::Vec<T, Size>> : public std::is_integral<T>
{
};
template <typename T, typename U>
struct IsIntegral<vtkm::Pair<T, U>>
: public std::integral_constant<bool, std::is_integral<T>::value && std::is_integral<U>::value>
{
};
// Generic implementation:
template <typename PortalT, typename ReturnType, typename Functor>
static ReturnType Execute(PortalT portal, ReturnType init, Functor functorIn, std::false_type)
@ -279,8 +308,8 @@ struct ReduceHelper
int numThreads = 0;
std::unique_ptr<ReturnType[]> threadData;
VTKM_OPENMP_DIRECTIVE(parallel default(none) firstprivate(f)
shared(data, doParallel, numThreads, threadData))
VTKM_OPENMP_DIRECTIVE(parallel default(none) firstprivate(f) shared(
data, doParallel, numThreads, threadData) VTKM_OPENMP_SHARED_CONST(numVals))
{
int tid = omp_get_thread_num();
@ -297,18 +326,11 @@ struct ReduceHelper
if (doParallel)
{
// Use the first (numThreads*2) values for initializing:
ReturnType accum;
accum = f(data[2 * tid], data[2 * tid + 1]);
// Static dispatch to unroll non-integral types:
const ReturnType localResult = ReduceHelper::DoParallelReduction<ReturnType>(
data, numVals, tid, numThreads, f, IsIntegral<ReturnType>{});
// Assign each thread chunks of the remaining values for local reduction
VTKM_OPENMP_DIRECTIVE(for schedule(static))
for (vtkm::Id i = numThreads * 2; i < numVals; i++)
{
accum = f(accum, data[i]);
}
threadData[static_cast<std::size_t>(tid)] = accum;
threadData[static_cast<std::size_t>(tid)] = localResult;
}
} // end parallel
@ -332,6 +354,64 @@ struct ReduceHelper
return init;
}
// non-integer reduction: unroll loop manually.
// This gives faster code for floats and non-trivial types.
template <typename ReturnType, typename IterType, typename FunctorType>
static ReturnType DoParallelReduction(IterType data,
vtkm::Id numVals,
int tid,
int numThreads,
FunctorType f,
std::false_type /* isIntegral */)
{
// Use the first (numThreads*2) values for initializing:
ReturnType accum = f(data[2 * tid], data[2 * tid + 1]);
vtkm::Id i = numThreads * 2;
const vtkm::Id unrollEnd = (numVals / 4) * 4;
VTKM_OPENMP_DIRECTIVE(for schedule(static))
for (i = numThreads * 2; i < unrollEnd; i += 4)
{
const auto t1 = f(data[i], data[i + 1]);
const auto t2 = f(data[i + 2], data[i + 3]);
accum = f(accum, t1);
accum = f(accum, t2);
}
// Let thread 0 mop up any remaining values:
if (tid == 0)
{
for (i = unrollEnd; i < numVals; ++i)
{
accum = f(accum, data[i]);
}
}
return accum;
}
// Integer reduction: no unrolling. Ints vectorize easily and unrolling can
// hurt performance.
template <typename ReturnType, typename IterType, typename FunctorType>
static ReturnType DoParallelReduction(IterType data,
vtkm::Id numVals,
int tid,
int numThreads,
FunctorType f,
std::true_type /* isIntegral */)
{
// Use the first (numThreads*2) values for initializing:
ReturnType accum = f(data[2 * tid], data[2 * tid + 1]);
// Assign each thread chunks of the remaining values for local reduction
VTKM_OPENMP_DIRECTIVE(for schedule(static))
for (vtkm::Id i = numThreads * 2; i < numVals; i++)
{
accum = f(accum, data[i]);
}
return accum;
}
#ifdef VTKM_OPENMP_USE_NATIVE_REDUCTION
// Specialize for vtkm functors with OpenMP special cases:
@ -412,7 +492,7 @@ void ReduceByKeyHelper(KeysInArray keysInArray,
vtkm::Id outIdx = 0;
VTKM_OPENMP_DIRECTIVE(parallel default(none) firstprivate(keysIn, valuesIn, keysOut, valuesOut, f)
shared(outIdx))
shared(outIdx) VTKM_OPENMP_SHARED_CONST(numValues))
{
int tid = omp_get_thread_num();
int numThreads = omp_get_num_threads();

@ -123,7 +123,8 @@ void parallel_sort_bykey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
VTKM_OPENMP_DIRECTIVE(parallel for
default(none)
firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
schedule(static))
schedule(static)
VTKM_OPENMP_SHARED_CONST(size))
for (vtkm::Id i = 0; i < size; ++i)
{
valuesOutPortal.Set(i, valuesInPortal.Get(indexPortal.Get(i)));
@ -209,6 +210,7 @@ void parallel_sort_bykey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
VTKM_OPENMP_DIRECTIVE(parallel for
default(none)
firstprivate(valuesInPortal, indexPortal, valuesOutPortal)
VTKM_OPENMP_SHARED_CONST(size)
schedule(static))
for (vtkm::Id i = 0; i < size; ++i)
{

@ -11,6 +11,7 @@
set(unit_tests
UnitTestOpenMPArrayHandle.cxx
UnitTestOpenMPArrayHandleFancy.cxx
UnitTestOpenMPArrayHandleMultiplexer.cxx
UnitTestOpenMPArrayHandleVirtualCoordinates.cxx
UnitTestOpenMPBitField.cxx
UnitTestOpenMPCellLocatorRectilinearGrid.cxx

@ -0,0 +1,19 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/openmp/DeviceAdapterOpenMP.h>
#include <vtkm/cont/testing/TestingArrayHandleMultiplexer.h>
int UnitTestOpenMPArrayHandleMultiplexer(int argc, char* argv[])
{
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
return vtkm::cont::testing::TestingArrayHandleMultiplexer<
vtkm::cont::DeviceAdapterTagOpenMP>::Run(argc, argv);
}

@ -11,6 +11,7 @@
set(unit_tests
UnitTestSerialArrayHandle.cxx
UnitTestSerialArrayHandleFancy.cxx
UnitTestSerialArrayHandleMultiplexer.cxx
UnitTestSerialArrayHandleVirtualCoordinates.cxx
UnitTestSerialBitField.cxx
UnitTestSerialCellLocatorRectilinearGrid.cxx

@ -0,0 +1,21 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/testing/TestingArrayHandleMultiplexer.h>
int UnitTestSerialArrayHandleMultiplexer(int argc, char* argv[])
{
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagSerial{});
return vtkm::cont::testing::TestingArrayHandleMultiplexer<
vtkm::cont::DeviceAdapterTagSerial>::Run(argc, argv);
}

@ -11,6 +11,7 @@
set(unit_tests
UnitTestTBBArrayHandle.cxx
UnitTestTBBArrayHandleFancy.cxx
UnitTestTBBArrayHandleMultiplexer.cxx
UnitTestTBBArrayHandleVirtualCoordinates.cxx
UnitTestTBBBitField.cxx
UnitTestTBBCellLocatorRectilinearGrid.cxx

@ -0,0 +1,20 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
#include <vtkm/cont/testing/TestingArrayHandleMultiplexer.h>
int UnitTestTBBArrayHandleMultiplexer(int argc, char* argv[])
{
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagTBB{});
return vtkm::cont::testing::TestingArrayHandleMultiplexer<vtkm::cont::DeviceAdapterTagTBB>::Run(
argc, argv);
}

@ -13,6 +13,7 @@ set(headers
MakeTestDataSet.h
Testing.h
TestingArrayHandles.h
TestingArrayHandleMultiplexer.h
TestingArrayHandleVirtualCoordinates.h
TestingCellLocatorRectilinearGrid.h
TestingCellLocatorUniformBins.h

@ -0,0 +1,158 @@
//============================================================================
// 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_cont_testing_TestingArrayHandleMultiplexer_h
#define vtk_m_cont_testing_TestingArrayHandleMultiplexer_h
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/testing/Testing.h>
namespace vtkm
{
namespace cont
{
namespace testing
{
template <typename T>
struct TestValueFunctor
{
VTKM_EXEC_CONT T operator()(vtkm::Id index) const { return TestValue(index, T()); }
};
template <typename DeviceAdapter>
class TestingArrayHandleMultiplexer
{
static constexpr vtkm::Id ARRAY_SIZE = 10;
template <typename... Ts0, typename... Ts1>
static void CheckArray(const vtkm::cont::ArrayHandleMultiplexer<Ts0...>& multiplexerArray,
const vtkm::cont::ArrayHandle<Ts1...>& expectedArray)
{
using T = typename std::remove_reference<decltype(multiplexerArray)>::type::ValueType;
vtkm::cont::printSummary_ArrayHandle(multiplexerArray, std::cout);
VTKM_TEST_ASSERT(test_equal_portals(multiplexerArray.GetPortalConstControl(),
expectedArray.GetPortalConstControl()),
"Multiplexer array gave wrong result in control environment");
vtkm::cont::ArrayHandle<T> copy;
vtkm::cont::ArrayCopy(multiplexerArray, copy);
VTKM_TEST_ASSERT(
test_equal_portals(copy.GetPortalConstControl(), expectedArray.GetPortalConstControl()),
"Multiplexer did not copy correctly in execution environment");
}
static void BasicSwitch()
{
std::cout << std::endl << "--- Basic switch" << std::endl;
using ValueType = vtkm::FloatDefault;
using ArrayType1 = vtkm::cont::ArrayHandleConstant<ValueType>;
ArrayType1 array1(TestValue(0, vtkm::FloatDefault{}), ARRAY_SIZE);
using ArrayType2 = vtkm::cont::ArrayHandleCounting<ValueType>;
ArrayType2 array2(TestValue(1, vtkm::FloatDefault{}), 1.0f, ARRAY_SIZE);
auto array3 = vtkm::cont::make_ArrayHandleImplicit(TestValueFunctor<ValueType>{}, ARRAY_SIZE);
using ArrayType3 = decltype(array3);
vtkm::cont::ArrayHandleMultiplexer<ArrayType1, ArrayType2, ArrayType3> multiplexer;
std::cout << "Check array1" << std::endl;
multiplexer = array1;
CheckArray(multiplexer, array1);
std::cout << "Check array2" << std::endl;
multiplexer = array2;
CheckArray(multiplexer, array2);
std::cout << "Check array3" << std::endl;
multiplexer = array3;
CheckArray(multiplexer, array3);
}
static void DefaultScalar()
{
std::cout << std::endl << "--- Default list for scalars" << std::endl;
using ValueType = vtkm::FloatDefault;
vtkm::cont::ArrayHandleMultiplexer<ValueType> multiplexer;
std::cout << "Basic array type." << std::endl;
vtkm::cont::ArrayHandle<ValueType> baseArray;
baseArray.Allocate(ARRAY_SIZE);
SetPortal(baseArray.GetPortalControl());
multiplexer = baseArray;
CheckArray(multiplexer, baseArray);
std::cout << "Cast array type." << std::endl;
vtkm::cont::ArrayHandle<vtkm::UInt8> castArray;
castArray.Allocate(ARRAY_SIZE);
SetPortal(castArray.GetPortalControl());
multiplexer = vtkm::cont::make_ArrayHandleCast<ValueType>(castArray);
CheckArray(multiplexer, castArray);
}
static void DefaultVec3()
{
std::cout << std::endl << "--- Default list for Vec3" << std::endl;
using ValueType = vtkm::Vec<vtkm::FloatDefault, 3>;
vtkm::cont::ArrayHandleMultiplexer<ValueType> multiplexer;
std::cout << "Basic array type." << std::endl;
vtkm::cont::ArrayHandle<ValueType> baseArray;
baseArray.Allocate(ARRAY_SIZE);
SetPortal(baseArray.GetPortalControl());
multiplexer = baseArray;
CheckArray(multiplexer, baseArray);
std::cout << "Cast array type." << std::endl;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> castArray;
castArray.Allocate(ARRAY_SIZE);
SetPortal(castArray.GetPortalControl());
multiplexer = vtkm::cont::make_ArrayHandleCast<ValueType>(castArray);
CheckArray(multiplexer, castArray);
std::cout << "Uniform point coordinates" << std::endl;
vtkm::cont::ArrayHandleUniformPointCoordinates uniformCoords(vtkm::Id3(3));
multiplexer = uniformCoords;
CheckArray(multiplexer, uniformCoords);
}
static void TestAll()
{
BasicSwitch();
DefaultScalar();
DefaultVec3();
}
public:
static int Run(int argc, char* argv[])
{
vtkm::cont::ScopedRuntimeDeviceTracker device(DeviceAdapter{});
return vtkm::cont::testing::Testing::Run(TestAll, argc, argv);
}
};
}
}
} // namespace vtkm::cont::testing
#endif //vtk_m_cont_testing_TestingArrayHandleMultiplexer_h

@ -681,6 +681,37 @@ private:
}
};
struct TestCastAsOutput
{
template <typename CastFromType>
VTKM_CONT void operator()(CastFromType vtkmNotUsed(type)) const
{
using InputArrayType = vtkm::cont::ArrayHandleIndex;
using ResultArrayType = vtkm::cont::ArrayHandle<CastFromType>;
InputArrayType input(ARRAY_SIZE);
ResultArrayType result;
vtkm::cont::ArrayHandleCast<vtkm::Id, ResultArrayType> castArray =
vtkm::cont::make_ArrayHandleCast<CastFromType>(result);
vtkm::worklet::DispatcherMapField<PassThrough> dispatcher;
dispatcher.Invoke(input, castArray);
vtkm::cont::printSummary_ArrayHandle(castArray, std::cout);
std::cout << std::endl;
// verify results
vtkm::Id length = ARRAY_SIZE;
for (vtkm::Id i = 0; i < length; ++i)
{
VTKM_TEST_ASSERT(input.GetPortalConstControl().Get(i) ==
static_cast<vtkm::Id>(result.GetPortalConstControl().Get(i)),
"Casting ArrayHandle Failed");
}
}
};
template <vtkm::IdComponent NUM_COMPONENTS>
struct TestGroupVecAsInput
{
@ -1284,6 +1315,11 @@ private:
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsInput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleCast as Output" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsOutput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl;
vtkm::testing::Testing::TryTypes(

@ -108,6 +108,16 @@ public:
{
coordi.push_back(vtkm::make_Vec(dr(dre), dr(dre), dr(dre)));
}
// Add a point to each corner to test the case where points might slip out
// of the range by epsilon
coordi.push_back(vtkm::make_Vec(00.0f, 00.0f, 00.0f));
coordi.push_back(vtkm::make_Vec(00.0f, 10.0f, 00.0f));
coordi.push_back(vtkm::make_Vec(10.0f, 00.0f, 00.0f));
coordi.push_back(vtkm::make_Vec(10.0f, 10.0f, 00.0f));
coordi.push_back(vtkm::make_Vec(00.0f, 00.0f, 10.0f));
coordi.push_back(vtkm::make_Vec(00.0f, 10.0f, 10.0f));
coordi.push_back(vtkm::make_Vec(10.0f, 00.0f, 10.0f));
coordi.push_back(vtkm::make_Vec(10.0f, 10.0f, 10.0f));
auto coordi_Handle = vtkm::cont::make_ArrayHandle(coordi);
vtkm::cont::CoordinateSystem coord("points", coordi_Handle);
@ -126,6 +136,15 @@ public:
{
qcVec.push_back(vtkm::make_Vec(dr(dre), dr(dre), dr(dre)));
}
// Test near each corner to make sure that corner gets included
qcVec.push_back(vtkm::make_Vec(0.01f, 0.01f, 0.01f));
qcVec.push_back(vtkm::make_Vec(0.01f, 9.99f, 0.01f));
qcVec.push_back(vtkm::make_Vec(9.99f, 0.01f, 0.01f));
qcVec.push_back(vtkm::make_Vec(9.99f, 9.99f, 0.01f));
qcVec.push_back(vtkm::make_Vec(0.01f, 0.01f, 9.991f));
qcVec.push_back(vtkm::make_Vec(0.01f, 9.99f, 9.99f));
qcVec.push_back(vtkm::make_Vec(9.99f, 0.01f, 9.99f));
qcVec.push_back(vtkm::make_Vec(9.99f, 9.99f, 9.99f));
auto qc_Handle = vtkm::cont::make_ArrayHandle(qcVec);
vtkm::cont::ArrayHandle<vtkm::Id> nnId_Handle;

@ -109,6 +109,15 @@ struct TestArrayHandleCast
RunTest(array);
RunTest(MakeTestVariantArrayHandle(array));
}
template <typename T, vtkm::IdComponent N>
void operator()(vtkm::Vec<T, N>) const
{
auto array = vtkm::cont::make_ArrayHandleCast<vtkm::Vec<T, N>>(
RandomArrayHandle<vtkm::Vec<vtkm::Int8, N>>::Make(ArraySize));
RunTest(array);
RunTest(MakeTestVariantArrayHandle(array));
}
};
struct TestArrayHandleCompositeVector

@ -56,7 +56,6 @@ struct TemplatedTests
using ValueType = typename StorageType::ValueType;
using PortalType = typename StorageType::PortalType;
using IteratorType = typename PortalType::IteratorType;
void BasicAllocation()
{

@ -10,6 +10,7 @@
#ifndef vtk_m_exec_BoundaryState_h
#define vtk_m_exec_BoundaryState_h
#include <vtkm/Assert.h>
#include <vtkm/Math.h>
namespace vtkm
@ -38,7 +39,7 @@ struct BoundaryState
//@{
/// Returns true if a neighborhood of the given radius is contained within the bounds of the cell
/// set in the X, Y, or Z direction. Returns false if the neighborhood extends ouside of the
/// set in the X, Y, or Z direction. Returns false if the neighborhood extends outside of the
/// boundary of the data in the X, Y, or Z direction.
///
/// The radius defines the size of the neighborhood in terms of how far away it extends from the
@ -46,22 +47,25 @@ struct BoundaryState
/// each direction and is 3x3x3. If there is a radius of 2, the neighborhood extends 2 units for
/// a size of 5x5x5.
///
VTKM_EXEC bool InXBoundary(vtkm::IdComponent radius) const
VTKM_EXEC bool IsRadiusInXBoundary(vtkm::IdComponent radius) const
{
VTKM_ASSERT(radius >= 0);
return (((this->IJK[0] - radius) >= 0) && ((this->IJK[0] + radius) < this->PointDimensions[0]));
}
VTKM_EXEC bool InYBoundary(vtkm::IdComponent radius) const
VTKM_EXEC bool IsRadiusInYBoundary(vtkm::IdComponent radius) const
{
VTKM_ASSERT(radius >= 0);
return (((this->IJK[1] - radius) >= 0) && ((this->IJK[1] + radius) < this->PointDimensions[1]));
}
VTKM_EXEC bool InZBoundary(vtkm::IdComponent radius) const
VTKM_EXEC bool IsRadiusInZBoundary(vtkm::IdComponent radius) const
{
VTKM_ASSERT(radius >= 0);
return (((this->IJK[2] - radius) >= 0) && ((this->IJK[2] + radius) < this->PointDimensions[2]));
}
//@}
/// Returns true if a neighborhood of the given radius is contained within the bounds
/// of the cell set. Returns false if the neighborhood extends ouside of the boundary of the
/// of the cell set. Returns false if the neighborhood extends outside of the boundary of the
/// data.
///
/// The radius defines the size of the neighborhood in terms of how far away it extends from the
@ -69,15 +73,47 @@ struct BoundaryState
/// each direction and is 3x3x3. If there is a radius of 2, the neighborhood extends 2 units for
/// a size of 5x5x5.
///
VTKM_EXEC bool InBoundary(vtkm::IdComponent radius) const
VTKM_EXEC bool IsRadiusInBoundary(vtkm::IdComponent radius) const
{
return this->InXBoundary(radius) && this->InYBoundary(radius) && this->InZBoundary(radius);
return this->IsRadiusInXBoundary(radius) && this->IsRadiusInYBoundary(radius) &&
this->IsRadiusInZBoundary(radius);
}
//@{
/// Returns true if the neighbor at the specified @a offset is contained
/// within the bounds of the cell set in the X, Y, or Z direction. Returns
/// false if the neighbor falls outside of the boundary of the data in the X,
/// Y, or Z direction.
///
VTKM_EXEC bool IsNeighborInXBoundary(vtkm::IdComponent offset) const
{
return (((this->IJK[0] + offset) >= 0) && ((this->IJK[0] + offset) < this->PointDimensions[0]));
}
VTKM_EXEC bool IsNeighborInYBoundary(vtkm::IdComponent offset) const
{
return (((this->IJK[1] + offset) >= 0) && ((this->IJK[1] + offset) < this->PointDimensions[1]));
}
VTKM_EXEC bool IsNeighborInZBoundary(vtkm::IdComponent offset) const
{
return (((this->IJK[2] + offset) >= 0) && ((this->IJK[2] + offset) < this->PointDimensions[2]));
}
//@}
/// Returns true if the neighbor at the specified offset vector is contained
/// within the bounds of the cell set. Returns false if the neighbor falls
/// outside of the boundary of the data.
///
VTKM_EXEC bool IsNeighborInBoundary(const vtkm::Vec<vtkm::IdComponent, 3>& neighbor) const
{
return this->IsNeighborInXBoundary(neighbor[0]) && this->IsNeighborInYBoundary(neighbor[1]) &&
this->IsNeighborInZBoundary(neighbor[2]);
}
/// Returns the minimum neighborhood indices that are within the bounds of the data.
///
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> MinNeighborIndices(vtkm::IdComponent radius) const
{
VTKM_ASSERT(radius >= 0);
vtkm::Vec<vtkm::IdComponent, 3> minIndices;
for (vtkm::IdComponent component = 0; component < 3; ++component)
@ -99,6 +135,7 @@ struct BoundaryState
///
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> MaxNeighborIndices(vtkm::IdComponent radius) const
{
VTKM_ASSERT(radius >= 0);
vtkm::Vec<vtkm::IdComponent, 3> maxIndices;
for (vtkm::IdComponent component = 0; component < 3; ++component)
@ -117,9 +154,6 @@ struct BoundaryState
return maxIndices;
}
//todo: This needs to work with BoundaryConstantValue
//todo: This needs to work with BoundaryPeroidic
//@{
/// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size)
/// and returns the ijk of the equivalent point in the full data set. If the given value is out
@ -143,8 +177,29 @@ struct BoundaryState
}
//@}
//todo: This needs to work with BoundaryConstantValue
//todo: This needs to work with BoundaryPeroidic
//@{
/// Takes a local neighborhood index (in the ranges of -neighborhood size to
/// neighborhood size), clamps it to the dataset bounds, and returns a new
/// neighborhood index. For example, if given a neighbor index that is past
/// the minimum x range of the data, the neighbor index of the minimum x
/// boundary is returned.
///
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> ClampNeighborIndex(
const vtkm::Vec<vtkm::IdComponent, 3>& neighbor) const
{
const vtkm::Id3 fullIndex = this->IJK + neighbor;
const vtkm::Id3 clampedFullIndex =
vtkm::Max(vtkm::Id3(0), vtkm::Min(this->PointDimensions - vtkm::Id3(1), fullIndex));
return vtkm::Vec<vtkm::IdComponent, 3>{ clampedFullIndex - this->IJK };
}
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> ClampNeighborIndex(vtkm::IdComponent neighborI,
vtkm::IdComponent neighborJ,
vtkm::IdComponent neighborK) const
{
return this->ClampNeighborIndex(vtkm::make_Vec(neighborI, neighborJ, neighborK));
}
//@}
//@{
/// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size)

@ -57,3 +57,6 @@ add_subdirectory(cuda)
#-----------------------------------------------------------------------------
add_subdirectory(testing)
#-----------------------------------------------------------------------------
add_subdirectory(cellmetrics)

@ -80,10 +80,16 @@ public:
// TODO: This might stop looking before the absolute nearest neighbor is found.
vtkm::Id maxLevel = vtkm::Max(vtkm::Max(this->Dims[0], this->Dims[1]), this->Dims[2]);
for (vtkm::Id level = 1; (nearestNeighborId < 0) && (level < maxLevel); ++level)
vtkm::Id level;
for (level = 1; (nearestNeighborId < 0) && (level < maxLevel); ++level)
{
this->FindInBox(queryPoint, ijk, level, nearestNeighborId, distance2);
}
// Search one more level out. This is still not guaranteed to find the closest point
// in all cases (past level 2), but it will catch most cases where the closest point
// is just on the other side of a cell boundary.
this->FindInBox(queryPoint, ijk, level, nearestNeighborId, distance2);
}
private:
@ -143,7 +149,7 @@ private:
if ((boxCenter[1] + level) < this->Dims[1])
{
this->FindInYPlane(
queryPoint, boxCenter - vtkm::Id3(0, level, 0), level, nearestNeighborId, nearestDistance2);
queryPoint, boxCenter + vtkm::Id3(0, level, 0), level, nearestNeighborId, nearestDistance2);
}
if ((boxCenter[2] - level) >= 0)
@ -154,7 +160,7 @@ private:
if ((boxCenter[2] + level) < this->Dims[2])
{
this->FindInZPlane(
queryPoint, boxCenter - vtkm::Id3(0, 0, level), level, nearestNeighborId, nearestDistance2);
queryPoint, boxCenter + vtkm::Id3(0, 0, level), level, nearestNeighborId, nearestDistance2);
}
}

@ -44,23 +44,37 @@ void verify_neighbors(NeighborhoodType neighbors, vtkm::Id index, vtkm::Id3 inde
//Verify the boundary flags first
VTKM_TEST_ASSERT(((index3d[0] != 0) && (index3d[0] != (POINT_DIMS[0] - 1))) ==
boundary->InXBoundary(1),
"Got invalid X boundary");
boundary->IsRadiusInXBoundary(1),
"Got invalid X radius boundary");
VTKM_TEST_ASSERT(((index3d[1] != 0) && (index3d[1] != (POINT_DIMS[1] - 1))) ==
boundary->InYBoundary(1),
"Got invalid Y boundary");
boundary->IsRadiusInYBoundary(1),
"Got invalid Y radius boundary");
VTKM_TEST_ASSERT(((index3d[2] != 0) && (index3d[2] != (POINT_DIMS[2] - 1))) ==
boundary->InZBoundary(1),
"Got invalid Z boundary");
boundary->IsRadiusInZBoundary(1),
"Got invalid Z radius boundary");
VTKM_TEST_ASSERT((index3d[0] != 0) == boundary->IsNeighborInXBoundary(-1),
"Got invalid X negative neighbor boundary");
VTKM_TEST_ASSERT((index3d[1] != 0) == boundary->IsNeighborInYBoundary(-1),
"Got invalid Y negative neighbor boundary");
VTKM_TEST_ASSERT((index3d[2] != 0) == boundary->IsNeighborInZBoundary(-1),
"Got invalid Z negative neighbor boundary");
VTKM_TEST_ASSERT((index3d[0] != (POINT_DIMS[0] - 1)) == boundary->IsNeighborInXBoundary(1),
"Got invalid X positive neighbor boundary");
VTKM_TEST_ASSERT((index3d[1] != (POINT_DIMS[1] - 1)) == boundary->IsNeighborInYBoundary(1),
"Got invalid Y positive neighbor boundary");
VTKM_TEST_ASSERT((index3d[2] != (POINT_DIMS[2] - 1)) == boundary->IsNeighborInZBoundary(1),
"Got invalid Z positive neighbor boundary");
VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[0] == -1) &&
(boundary->MaxNeighborIndices(1)[0] == 1)) == boundary->InXBoundary(1),
(boundary->MaxNeighborIndices(1)[0] == 1)) == boundary->IsRadiusInXBoundary(1),
"Got invalid min/max X indices");
VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[1] == -1) &&
(boundary->MaxNeighborIndices(1)[1] == 1)) == boundary->InYBoundary(1),
(boundary->MaxNeighborIndices(1)[1] == 1)) == boundary->IsRadiusInYBoundary(1),
"Got invalid min/max Y indices");
VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[2] == -1) &&
(boundary->MaxNeighborIndices(1)[2] == 1)) == boundary->InZBoundary(1),
(boundary->MaxNeighborIndices(1)[2] == 1)) == boundary->IsRadiusInZBoundary(1),
"Got invalid min/max Z indices");
T forwardX = neighbors.Get(1, 0, 0);

@ -0,0 +1,28 @@
##============================================================================
## Copyright (c) Kitware, Inc.
## All rights reserved.
## See LICENSE.txt for details.
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
##
## Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
## Copyright 2014 UT-Battelle, LLC.
## Copyright 2014 Los Alamos National Security.
##
## Under the terms of Contract DE-NA0003525 with NTESS,
## the U.S. Government retains certain rights in this software.
##
## Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
## Laboratory (LANL), the U.S. Government retains certain rights in
## this software.
##============================================================================
set(headers
CellDiagonalRatioMetric.h
CellEdgeRatioMetric.h
)
#-----------------------------------------------------------------------------
vtkm_declare_headers(${headers})

@ -0,0 +1,236 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2018 UT-Battelle, LLC.
// Copyright 2018 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_exec_cellmetrics_CellDiagonalRatioMetric_h
#define vtk_m_exec_cellmetrics_CellDiagonalRatioMetric_h
/*
* Mesh quality metric functions that compute the diagonal ratio of mesh cells.
* The diagonal ratio of a cell is defined as the length (magnitude) of the longest
* cell diagonal length divided by the length of the shortest cell diagonal length.
*
* These metric computations are adapted from the VTK implementation of the Verdict library,
* which provides a set of mesh/cell metrics for evaluating the geometric qualities of regions
* of mesh spaces.
*
* The edge ratio computations for a pyramid cell types is not defined in the
* VTK implementation, but is provided here.
*
* See: The Verdict Library Reference Manual (for per-cell-type metric formulae)
* See: vtk/ThirdParty/verdict/vtkverdict (for VTK code implementation of this metric)
*/
#include "vtkm/CellShape.h"
#include "vtkm/CellTraits.h"
#include "vtkm/VecTraits.h"
#include "vtkm/VectorAnalysis.h"
#include "vtkm/exec/FunctorBase.h"
#define UNUSED(expr) (void)(expr);
namespace vtkm
{
namespace exec
{
namespace cellmetrics
{
using FloatType = vtkm::FloatDefault;
template <typename OutType, typename VecType>
VTKM_EXEC inline OutType ComputeDiagonalRatio(const VecType& diagonals)
{
const vtkm::Id numDiagonals = diagonals.GetNumberOfComponents();
//Compare diagonal lengths to determine the longest and shortest
//TODO: Could we use lambda expression here?
FloatType d0Len = (FloatType)vtkm::MagnitudeSquared(diagonals[0]);
FloatType currLen, minLen = d0Len, maxLen = d0Len;
for (int i = 1; i < numDiagonals; i++)
{
currLen = (FloatType)vtkm::MagnitudeSquared(diagonals[i]);
if (currLen < minLen)
minLen = currLen;
if (currLen > maxLen)
maxLen = currLen;
}
if (minLen < vtkm::NegativeInfinity<FloatType>())
return vtkm::Infinity<OutType>();
//Take square root because we only did magnitude squared before
OutType diagonalRatio = (OutType)vtkm::Sqrt(maxLen / minLen);
if (diagonalRatio > 0)
return vtkm::Min(diagonalRatio, vtkm::Infinity<OutType>()); //normal case
return vtkm::Max(diagonalRatio, OutType(-1) * vtkm::Infinity<OutType>());
}
// ========================= Unsupported cells ==================================
// By default, cells have zero shape unless the shape type template is specialized below.
template <typename OutType, typename PointCoordVecType, typename CellShapeType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
CellShapeType shape,
const vtkm::exec::FunctorBase&)
{
UNUSED(numPts);
UNUSED(pts);
UNUSED(shape);
return OutType(0.0);
}
/*
//TODO: Should polygons be supported? Maybe call Quad or Triangle function...
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagPolygon,
const vtkm::exec::FunctorBase& worklet)
{
switch (numPts)
{
case 4:
return CellDiagonalRatioMetric<OutType>(numPts, pts, vtkm::CellShapeTagQuad(), worklet);
default:
break;
}
return OutType(-1.0);
}
*/
/*
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent&,
const PointCoordVecType&,
vtkm::CellShapeTagLine,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(worklet);
return OutType(-1.0);
}
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent&,
const PointCoordVecType&,
vtkm::CellShapeTagTriangle,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(worklet);
return OutType(-1.0);
}
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent&,
const PointCoordVecType&,
vtkm::CellShapeTagTetra,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(worklet);
return OutType(-1.0);
}
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent&,
const PointCoordVecType&,
vtkm::CellShapeTagWedge,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(worklet);
return OutType(-1.0);
}
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent&,
const PointCoordVecType&,
vtkm::CellShapeTagPyramid,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(worklet);
return OutType(-1.0);
}
*/
// ========================= 2D cells ==================================
// Compute the diagonal ratio of a quadrilateral.
// Formula: Maximum diagonal length divided by minimum diagonal length
// Equals 1 for a unit square
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagQuad,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 4)
{
worklet.RaiseError("Diagonal ratio metric(quad) requires 4 points.");
return OutType(0.0);
}
vtkm::IdComponent numDiagonals = 2; //pts.GetNumberOfComponents();
//The 2 diagonals of a quadrilateral
using Diagonal = typename PointCoordVecType::ComponentType;
const Diagonal QuadDiagonals[2] = { pts[2] - pts[0], pts[3] - pts[1] };
return vtkm::exec::cellmetrics::ComputeDiagonalRatio<OutType>(
vtkm::make_VecC(QuadDiagonals, numDiagonals));
}
// ============================= 3D Volume cells ==================================
// Compute the diagonal ratio of a hexahedron.
// Formula: Maximum diagonal length divided by minimum diagonal length
// Equals 1 for a unit cube
// Acceptable Range: [0.65, 1]
// Normal Range: [0, 1]
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellDiagonalRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagHexahedron,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 8)
{
worklet.RaiseError("Diagonal ratio metric(hexahedron) requires 8 points.");
return OutType(0.0);
}
vtkm::IdComponent numDiagonals = 4; //pts.GetNumberOfComponents();
//The 4 diagonals of a hexahedron
using Diagonal = typename PointCoordVecType::ComponentType;
const Diagonal HexDiagonals[4] = {
pts[6] - pts[0], pts[7] - pts[1], pts[4] - pts[2], pts[5] - pts[3]
};
return vtkm::exec::cellmetrics::ComputeDiagonalRatio<OutType>(
vtkm::make_VecC(HexDiagonals, numDiagonals));
}
} // namespace cellmetrics
} // namespace exec
} // namespace vtkm
#endif // vtk_m_exec_cellmetrics_CellEdgeRatioMetric_h

@ -0,0 +1,299 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_exec_cellmetrics_CellEdgeRatioMetric_h
#define vtk_m_exec_cellmetrics_CellEdgeRatioMetric_h
/*
* Mesh quality metric functions that compute the edge ratio of mesh cells.
* The edge ratio of a cell is defined as the length (magnitude) of the longest
* cell edge divided by the length of the shortest cell edge.
*
* These metric computations are adapted from the VTK implementation of the Verdict library,
* which provides a set of mesh/cell metrics for evaluating the geometric qualities of regions
* of mesh spaces.
*
* The edge ratio computations for a pyramid cell types is not defined in the
* VTK implementation, but is provided here.
*
* See: The Verdict Library Reference Manual (for per-cell-type metric formulae)
* See: vtk/ThirdParty/verdict/vtkverdict (for VTK code implementation of this metric)
*/
#include "vtkm/CellShape.h"
#include "vtkm/CellTraits.h"
#include "vtkm/VecTraits.h"
#include "vtkm/VectorAnalysis.h"
#include "vtkm/exec/FunctorBase.h"
#define UNUSED(expr) (void)(expr);
namespace vtkm
{
namespace exec
{
namespace cellmetrics
{
using FloatType = vtkm::FloatDefault;
template <typename OutType, typename VecType>
VTKM_EXEC inline OutType ComputeEdgeRatio(const VecType& edges)
{
const vtkm::Id numEdges = edges.GetNumberOfComponents();
//Compare edge lengths to determine the longest and shortest
//TODO: Could we use lambda expression here?
FloatType e0Len = (FloatType)vtkm::MagnitudeSquared(edges[0]);
FloatType currLen, minLen = e0Len, maxLen = e0Len;
for (int i = 1; i < numEdges; i++)
{
currLen = (FloatType)vtkm::MagnitudeSquared(edges[i]);
if (currLen < minLen)
minLen = currLen;
if (currLen > maxLen)
maxLen = currLen;
}
if (minLen < vtkm::NegativeInfinity<FloatType>())
return vtkm::Infinity<OutType>();
//Take square root because we only did magnitude squared before
OutType edgeRatio = (OutType)vtkm::Sqrt(maxLen / minLen);
if (edgeRatio > 0)
return vtkm::Min(edgeRatio, vtkm::Infinity<OutType>()); //normal case
return vtkm::Max(edgeRatio, OutType(-1) * vtkm::Infinity<OutType>());
}
// ========================= Unsupported cells ==================================
// By default, cells have zero shape unless the shape type template is specialized below.
template <typename OutType, typename PointCoordVecType, typename CellShapeType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
CellShapeType shape,
const vtkm::exec::FunctorBase&)
{
UNUSED(numPts);
UNUSED(pts);
UNUSED(shape);
return OutType(0.0);
}
// ========================= 2D cells ==================================
// Compute the edge ratio of a line.
// Formula: Maximum edge length divided by minimum edge length
// Trivially equals 1, since only a single edge
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagLine,
const vtkm::exec::FunctorBase& worklet)
{
UNUSED(pts);
if (numPts < 2)
{
worklet.RaiseError("Degenerate line has no edge ratio.");
return OutType(0.0);
}
return OutType(1.0);
}
// Compute the edge ratio of a triangle.
// Formula: Maximum edge length divided by minimum edge length
// Equals 1 for an equilateral unit triangle
// Acceptable range: [1,1.3]
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagTriangle,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 3)
{
worklet.RaiseError("Edge ratio metric(triangle) requires 3 points.");
return OutType(0.0);
}
const vtkm::IdComponent numEdges = 3; //pts.GetNumberOfComponents();
//The 3 edges of a triangle
using Edge = typename PointCoordVecType::ComponentType;
const Edge TriEdges[3] = { pts[1] - pts[0], pts[2] - pts[1], pts[0] - pts[2] };
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(vtkm::make_VecC(TriEdges, numEdges));
}
// Compute the edge ratio of a quadrilateral.
// Formula: Maximum edge length divided by minimum edge length
// Equals 1 for a unit square
// Acceptable range: [1,1.3]
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagQuad,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 4)
{
worklet.RaiseError("Edge ratio metric(quad) requires 4 points.");
return OutType(0.0);
}
vtkm::IdComponent numEdges = 4; //pts.GetNumberOfComponents();
//The 4 edges of a quadrilateral
using Edge = typename PointCoordVecType::ComponentType;
const Edge QuadEdges[4] = { pts[1] - pts[0], pts[2] - pts[1], pts[3] - pts[2], pts[0] - pts[3] };
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(vtkm::make_VecC(QuadEdges, numEdges));
}
// ============================= 3D Volume cells ==================================i
// Compute the edge ratio of a tetrahedron.
// Formula: Maximum edge length divided by minimum edge length
// Equals 1 for a unit equilateral tetrahedron
// Acceptable range: [1,3]
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagTetra,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 4)
{
worklet.RaiseError("Edge ratio metric(tetrahedron) requires 4 points.");
return OutType(0.0);
}
vtkm::IdComponent numEdges = 6; //pts.GetNumberOfComponents();
//The 6 edges of a tetrahedron
using Edge = typename PointCoordVecType::ComponentType;
const Edge TetEdges[6] = { pts[1] - pts[0], pts[2] - pts[1], pts[0] - pts[2],
pts[3] - pts[0], pts[3] - pts[1], pts[3] - pts[2] };
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(vtkm::make_VecC(TetEdges, numEdges));
}
// Compute the edge ratio of a hexahedron.
// Formula: Maximum edge length divided by minimum edge length
// Equals 1 for a unit cube
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagHexahedron,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 8)
{
worklet.RaiseError("Edge ratio metric(hexahedron) requires 8 points.");
return OutType(0.0);
}
vtkm::IdComponent numEdges = 12; //pts.GetNumberOfComponents();
//The 12 edges of a hexahedron
using Edge = typename PointCoordVecType::ComponentType;
const Edge HexEdges[12] = { pts[1] - pts[0], pts[2] - pts[1], pts[3] - pts[2], pts[0] - pts[3],
pts[5] - pts[4], pts[6] - pts[5], pts[7] - pts[6], pts[4] - pts[7],
pts[4] - pts[0], pts[5] - pts[1], pts[6] - pts[2], pts[7] - pts[3] };
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(vtkm::make_VecC(HexEdges, numEdges));
}
// Compute the edge ratio of a wedge/prism.
// Formula: Maximum edge length divided by minimum edge length
// Equals 1 for a right unit wedge
// Full range: [1,FLOAT_MAX]
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagWedge,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 6)
{
worklet.RaiseError("Edge ratio metric(wedge) requires 6 points.");
return OutType(0.0);
}
vtkm::IdComponent numEdges = 9; //pts.GetNumberOfComponents();
//The 9 edges of a wedge/prism
using Edge = typename PointCoordVecType::ComponentType;
const Edge WedgeEdges[9] = { pts[1] - pts[0], pts[2] - pts[1], pts[0] - pts[2],
pts[4] - pts[3], pts[5] - pts[4], pts[3] - pts[5],
pts[3] - pts[0], pts[4] - pts[1], pts[5] - pts[2] };
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(vtkm::make_VecC(WedgeEdges, numEdges));
}
// Compute the edge ratio of a pyramid.
// Formula: Maximum edge length divided by minimum edge length
// TODO: Equals 1 for a right unit (square base?) pyramid (?)
// Full range: [1,FLOAT_MAX]
// TODO: Verdict/VTK don't define this metric for a pyramid. What does VisIt output?
template <typename OutType, typename PointCoordVecType>
VTKM_EXEC OutType CellEdgeRatioMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
vtkm::CellShapeTagPyramid,
const vtkm::exec::FunctorBase& worklet)
{
if (numPts != 5)
{
worklet.RaiseError("Edge ratio metric(pyramid) requires 5 points.");
return OutType(0.0);
}
vtkm::IdComponent numEdges = 8; // pts.GetNumberOfComponents();
//The 8 edges of a pyramid (4 quadrilateral base edges + 4 edges to apex)
using Edge = typename PointCoordVecType::ComponentType;
const Edge PyramidEdges[8] = {
pts[1] - pts[0], pts[2] - pts[1], pts[2] - pts[3], pts[3] - pts[0],
pts[4] - pts[0], pts[4] - pts[1], pts[4] - pts[2], pts[4] - pts[3]
};
return vtkm::exec::cellmetrics::ComputeEdgeRatio<OutType>(
vtkm::make_VecC(PyramidEdges, numEdges));
}
} // namespace cellmetrics
} // namespace exec
} // namespace vtkm
#endif // vtk_m_exec_cellmetrics_CellEdgeRatioMetric_h

@ -43,6 +43,7 @@ set(headers
MarchingCubes.h
Mask.h
MaskPoints.h
MeshQuality.h
NDEntropy.h
NDHistogram.h
OscillatorSource.h
@ -105,6 +106,7 @@ set(header_template_sources
MarchingCubes.hxx
Mask.hxx
MaskPoints.hxx
MeshQuality.hxx
NDEntropy.hxx
NDHistogram.hxx
OscillatorSource.hxx

101
vtkm/filter/MeshQuality.h Normal file

@ -0,0 +1,101 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_filter_MeshQuality_h
#define vtk_m_filter_MeshQuality_h
#include "vtkm/CellShape.h"
#include "vtkm/filter/FilterCell.h"
#include "vtkm/worklet/MeshQuality.h"
#include <vtkm/worklet/FieldStatistics.h>
namespace vtkm
{
namespace filter
{
//Names of the available cell metrics, for use in
//the output dataset fields
//TODO: static const?
static const std::string MetricNames[] = { "empty",
"diagonalRatio",
"edgeRatio",
//"skew",
"oddy",
"relativeSizeSquared",
"volume" };
//Different cell metrics available to use
//TODO: static const?
enum class CellMetric
{
EMPTY, //0
DIAGONAL_RATIO,
EDGE_RATIO,
ODDY,
RELATIVE_SIZE,
VOLUME,
NUMBER_OF_CELL_METRICS //(num metrics = NUMBER_OF_CELL_METRICS - 2)
};
/** \brief Computes the quality of an unstructured cell-based mesh. The quality is defined in terms of the
* summary statistics (frequency, mean, variance, min, max) of metrics computed over the mesh
* cells. One of several different metrics can be specified for a given cell type, and the mesh
* can consist of one or more different cell types. The resulting mesh quality is stored as one
* or more new fields in the output dataset of this filter, with a separate field for each cell type.
* Each field contains the metric summary statistics for the cell type.
* Summary statists with all 0 values imply that the specified metric does not support the cell type.
*/
class MeshQuality : public vtkm::filter::FilterCell<MeshQuality>
{
public:
using ShapeMetricsVecType = std::vector<vtkm::Pair<vtkm::UInt8, CellMetric>>;
VTKM_CONT MeshQuality(const ShapeMetricsVecType& metrics);
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& points,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
private:
//A user-assigned cell metric per shape/cell type
//Empty metric if not provided by user
//Length of vector is the number of different VTK-m cell types
std::vector<CellMetric> CellTypeMetrics;
};
template <>
class FilterTraits<vtkm::filter::MeshQuality>
{
public:
using InputFieldTypeList = vtkm::TypeListTagFieldVec3;
};
} // namespace filter
} // namespace vtkm
#include <vtkm/filter/MeshQuality.hxx>
#endif // vtk_m_filter_MeshQuality_h

258
vtkm/filter/MeshQuality.hxx Normal file

@ -0,0 +1,258 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//=========================================================================
#include "vtkm/cont/DynamicCellSet.h"
#include "vtkm/cont/ErrorFilterExecution.h"
#include "vtkm/cont/Field.h"
#include "vtkm/filter/internal/CreateResult.h"
#include "vtkm/worklet/DispatcherMapTopology.h"
#define DEBUG_PRINT
namespace vtkm
{
namespace filter
{
namespace debug
{
#ifdef DEBUG_PRINT
//----------------------------------------------------------------------------
template <typename T, typename S = vtkm::cont::DeviceAdapterId>
void MeshQualityDebug(const vtkm::cont::ArrayHandle<T, S>& outputArray, const char* name)
{
typedef vtkm::cont::internal::Storage<T, S> StorageType;
typedef typename StorageType::PortalConstType PortalConstType;
PortalConstType readPortal = outputArray.GetPortalConstControl();
vtkm::Id numElements = readPortal.GetNumberOfValues();
std::cout << name << "= " << numElements << " [";
for (vtkm::Id i = 0; i < numElements; i++)
std::cout << (int)readPortal.Get(i) << " ";
std::cout << "]\n";
}
#else
template <typename T, typename S>
void MeshQualityDebug(const vtkm::cont::ArrayHandle<T, S>& vtkmNotUsed(outputArray),
const char* vtkmNotUsed(name))
{
}
#endif
} // namespace debug
inline VTKM_CONT MeshQuality::MeshQuality(
const std::vector<vtkm::Pair<vtkm::UInt8, CellMetric>>& metrics)
: vtkm::filter::FilterCell<MeshQuality>()
{
this->SetUseCoordinateSystemAsField(true);
this->CellTypeMetrics.assign(vtkm::NUMBER_OF_CELL_SHAPES, CellMetric::EMPTY);
for (auto p : metrics)
this->CellTypeMetrics[p.first] = p.second;
}
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet MeshQuality::DoExecute(
const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& points,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
{
VTKM_ASSERT(fieldMeta.IsPointField());
using Algorithm = vtkm::cont::Algorithm;
using ShapeHandle = vtkm::cont::ArrayHandle<vtkm::UInt8>;
using IdHandle = vtkm::cont::ArrayHandle<vtkm::Id>;
using QualityWorklet = vtkm::worklet::MeshQuality<CellMetric>;
using FieldStatsWorklet = vtkm::worklet::FieldStatistics<T>;
//TODO: Should other cellset types be supported?
vtkm::cont::CellSetExplicit<> cellSet;
input.GetCellSet(this->GetActiveCellSetIndex()).CopyTo(cellSet);
ShapeHandle cellShapes =
cellSet.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
//Obtain the frequency counts of each cell type in the input dataset
IdHandle uniqueCellCounts;
ShapeHandle uniqueCellShapes, sortedShapes;
Algorithm::Copy(cellShapes, sortedShapes);
Algorithm::Sort(sortedShapes);
Algorithm::ReduceByKey(
sortedShapes,
vtkm::cont::make_ArrayHandleConstant(vtkm::Id(1), cellShapes.GetNumberOfValues()),
uniqueCellShapes,
uniqueCellCounts,
vtkm::Add());
std::cout << "uniqueCellCounts: " << uniqueCellCounts.GetNumberOfValues() << "\n";
const vtkm::Id numUniqueShapes = uniqueCellShapes.GetNumberOfValues();
auto uniqueCellShapesPortal = uniqueCellShapes.GetPortalConstControl();
auto numCellsPerShapePortal = uniqueCellCounts.GetPortalConstControl();
std::vector<vtkm::Id> tempCounts(vtkm::NUMBER_OF_CELL_SHAPES);
for (vtkm::Id i = 0; i < numUniqueShapes; i++)
tempCounts[uniqueCellShapesPortal.Get(i)] = numCellsPerShapePortal.Get(i);
IdHandle cellShapeCounts = vtkm::cont::make_ArrayHandle(tempCounts);
std::cout << "cellShapeCounts: " << cellShapeCounts.GetNumberOfValues() << "\n";
//Invoke the MeshQuality worklet
vtkm::cont::ArrayHandle<T> outArray;
vtkm::cont::ArrayHandle<CellMetric> cellMetrics = vtkm::cont::make_ArrayHandle(CellTypeMetrics);
std::cout << "cellMetrics: " << cellMetrics.GetNumberOfValues() << "\n";
vtkm::worklet::DispatcherMapTopology<QualityWorklet> dispatcher;
dispatcher.Invoke(
vtkm::filter::ApplyPolicy(cellSet, policy), cellShapeCounts, cellMetrics, points, outArray);
//Build the output dataset: a separate field for each cell type that has a specified metric
vtkm::cont::DataSet result;
result.CopyStructure(input); //clone of the input dataset
auto cellShapePortal = cellShapes.GetPortalConstControl();
auto metricValuesPortal = outArray.GetPortalConstControl();
const vtkm::Id numCells = outArray.GetNumberOfValues();
T currMetric = 0;
vtkm::UInt8 currShape = 0;
//Output metric values stored in separate containers
//based on shape type. Unsupported shape types in VTK-m
//are represented with an empty "placeholder" container.
std::vector<std::vector<T>> metricValsPerShape = {
{ /*placeholder*/ }, { /*vertices*/ }, { /*placeholder*/ }, { /*lines*/ },
{ /*placeholder*/ }, { /*triangles*/ }, { /*placeholder*/ }, { /*polygons*/ },
{ /*placeholder*/ }, { /*quads*/ }, { /*tetrahedrons*/ }, { /*placeholder*/ },
{ /*hexahedrons*/ }, { /*wedges*/ }, { /*pyramids*/ }
};
for (vtkm::Id metricArrayIndex = 0; metricArrayIndex < numCells; metricArrayIndex++)
{
currShape = cellShapePortal.Get(metricArrayIndex);
currMetric = metricValuesPortal.Get(metricArrayIndex);
metricValsPerShape[currShape].emplace_back(currMetric);
}
//Compute the mesh quality for each shape type. This consists
//of computing the summary statistics of the metric values for
//each cell of the given shape type.
std::string fieldName = "", metricName = "";
vtkm::UInt8 cellShape = 0;
vtkm::Id cellCount = 0;
bool skipShape = false;
for (vtkm::Id shapeIndex = 0; shapeIndex < numUniqueShapes; shapeIndex++)
{
cellShape = uniqueCellShapesPortal.Get(shapeIndex);
cellCount = numCellsPerShapePortal.Get(shapeIndex);
metricName = MetricNames[static_cast<vtkm::UInt8>(CellTypeMetrics[cellShape])];
//Skip over shapes with an empty/unspecified metric;
//don't include a field for them
if (CellTypeMetrics[cellShape] == CellMetric::EMPTY)
continue;
switch (cellShape)
{
case vtkm::CELL_SHAPE_EMPTY:
skipShape = true;
break;
case vtkm::CELL_SHAPE_VERTEX:
fieldName = "vertices";
break;
case vtkm::CELL_SHAPE_LINE:
fieldName = "lines";
break;
case vtkm::CELL_SHAPE_TRIANGLE:
fieldName = "triangles";
break;
case vtkm::CELL_SHAPE_POLYGON:
fieldName = "polygons";
break;
case vtkm::CELL_SHAPE_QUAD:
fieldName = "quads";
break;
case vtkm::CELL_SHAPE_TETRA:
fieldName = "tetrahedrons";
break;
case vtkm::CELL_SHAPE_HEXAHEDRON:
fieldName = "hexahedrons";
break;
case vtkm::CELL_SHAPE_WEDGE:
fieldName = "wedges";
break;
case vtkm::CELL_SHAPE_PYRAMID:
fieldName = "pyramids";
break;
default:
skipShape = true;
break;
}
//Skip over shapes of empty cell type; don't include a field for them
if (skipShape)
continue;
fieldName += "-" + metricName;
auto shapeMetricVals = metricValsPerShape[cellShape];
auto shapeMetricValsHandle = vtkm::cont::make_ArrayHandle(std::move(shapeMetricVals));
//Invoke the field stats worklet on the array of metric values for this shape type
typename FieldStatsWorklet::StatInfo statinfo;
FieldStatsWorklet().Run(shapeMetricValsHandle, statinfo);
//Retrieve summary stats from the output stats struct.
//These stats define the mesh quality with respect to this shape type.
std::vector<T> shapeMeshQuality = {
T(cellCount), statinfo.mean, statinfo.variance, statinfo.minimum, statinfo.maximum
};
//Append the summary stats into the output dataset as a new field
result.AddField(vtkm::cont::make_Field(fieldName,
vtkm::cont::Field::Association::CELL_SET,
"cells",
shapeMeshQuality,
vtkm::CopyFlag::On));
std::cout << "-----------------------------------------------------\n"
<< "Mesh quality of " << fieldName << ":\n"
<< "Number of cells: " << cellCount << "\n"
<< "Mean: " << statinfo.mean << "\n"
<< "Variance: " << statinfo.variance << "\n"
<< "Minimum: " << statinfo.minimum << "\n"
<< "Maximum: " << statinfo.maximum << "\n"
<< "-----------------------------------------------------\n";
}
auto metricValsPortal = outArray.GetPortalConstControl();
std::cout << "-----------------------------------------------------\n"
<< "Metric values - all cells:\n";
for (vtkm::Id v = 0; v < outArray.GetNumberOfValues(); v++)
std::cout << metricValsPortal.Get(v) << "\n";
std::cout << "-----------------------------------------------------\n";
//Append the metric values of all cells into the output
//dataset as a new field
std::string s = "allCells-metricValues";
result.AddField(
vtkm::cont::Field(s, vtkm::cont::Field::Association::CELL_SET, "cells", outArray));
return result;
}
} // namespace filter
} // namespace vtkm

@ -37,6 +37,7 @@ set(unit_tests
UnitTestMarchingCubesFilter.cxx
UnitTestMaskFilter.cxx
UnitTestMaskPointsFilter.cxx
UnitTestMeshQualityFilter.cxx
UnitTestMultiBlockFilters.cxx
UnitTestMultiBlockHistogramFilter.cxx
UnitTestNDEntropyFilter.cxx

@ -0,0 +1,376 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2018 UT-Battelle, LLC.
// Copyright 2018 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <string>
#include <typeinfo>
#include <vector>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/MeshQuality.h>
#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/io/writer/VTKDataSetWriter.h>
//Adapted from vtkm/cont/testing/MakeTestDataSet.h
//Modified the content of the Make3DExplicitDataSetZoo() function
inline vtkm::cont::DataSet Make3DExplicitDataSet()
{
vtkm::cont::DataSet dataSet;
vtkm::cont::DataSetBuilderExplicit dsb;
using CoordType = vtkm::Vec<vtkm::Float64, 3>;
std::vector<CoordType> coords = {
{ 0.00, 0.00, 0.00 }, { 1.00, 0.00, 0.00 }, { 2.00, 0.00, 0.00 }, { 0.00, 0.00, 1.00 },
{ 1.00, 0.00, 1.00 }, { 2.00, 0.00, 1.00 }, { 0.00, 1.00, 0.00 }, { 1.00, 1.00, 0.00 },
{ 2.00, 1.00, 0.00 }, { 0.00, 1.00, 1.00 }, { 1.00, 1.00, 1.00 }, { 2.00, 1.00, 1.00 },
{ 0.00, 2.00, 0.00 }, { 1.00, 2.00, 0.00 }, { 2.00, 2.00, 0.00 }, { 0.00, 2.00, 1.00 },
{ 1.00, 2.00, 1.00 }, { 2.00, 2.00, 1.00 }, { 1.00, 3.00, 1.00 }, { 2.75, 0.00, 1.00 },
{ 3.00, 0.00, 0.75 }, { 3.00, 0.25, 1.00 }, { 3.00, 1.00, 1.00 }, { 3.00, 1.00, 0.00 },
{ 2.57, 2.00, 1.00 }, { 3.00, 1.75, 1.00 }, { 3.00, 1.75, 0.75 }, { 3.00, 0.00, 0.00 },
{ 2.57, 0.42, 0.57 }, { 2.59, 1.43, 0.71 }
};
std::vector<vtkm::UInt8> shapes;
std::vector<vtkm::IdComponent> numindices;
std::vector<vtkm::Id> conn;
//Construct the shapes/cells of the dataset
//This is a zoo of points, lines, polygons, and polyhedra
shapes.push_back(vtkm::CELL_SHAPE_HEXAHEDRON);
numindices.push_back(8);
conn.push_back(0);
conn.push_back(3);
conn.push_back(4);
conn.push_back(1);
conn.push_back(6);
conn.push_back(9);
conn.push_back(10);
conn.push_back(7);
shapes.push_back(vtkm::CELL_SHAPE_HEXAHEDRON);
numindices.push_back(8);
conn.push_back(1);
conn.push_back(4);
conn.push_back(5);
conn.push_back(2);
conn.push_back(7);
conn.push_back(10);
conn.push_back(11);
conn.push_back(8);
shapes.push_back(vtkm::CELL_SHAPE_TETRA);
numindices.push_back(4);
conn.push_back(24);
conn.push_back(26);
conn.push_back(25);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_TETRA);
numindices.push_back(4);
conn.push_back(8);
conn.push_back(17);
conn.push_back(11);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_PYRAMID);
numindices.push_back(5);
conn.push_back(24);
conn.push_back(17);
conn.push_back(8);
conn.push_back(23);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_PYRAMID);
numindices.push_back(5);
conn.push_back(25);
conn.push_back(22);
conn.push_back(11);
conn.push_back(17);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_WEDGE);
numindices.push_back(6);
conn.push_back(8);
conn.push_back(14);
conn.push_back(17);
conn.push_back(7);
conn.push_back(13);
conn.push_back(16);
shapes.push_back(vtkm::CELL_SHAPE_WEDGE);
numindices.push_back(6);
conn.push_back(11);
conn.push_back(8);
conn.push_back(17);
conn.push_back(10);
conn.push_back(7);
conn.push_back(16);
shapes.push_back(vtkm::CELL_SHAPE_VERTEX);
numindices.push_back(1);
conn.push_back(0);
shapes.push_back(vtkm::CELL_SHAPE_VERTEX);
numindices.push_back(1);
conn.push_back(29);
shapes.push_back(vtkm::CELL_SHAPE_LINE);
numindices.push_back(2);
conn.push_back(0);
conn.push_back(1);
shapes.push_back(vtkm::CELL_SHAPE_LINE);
numindices.push_back(2);
conn.push_back(15);
conn.push_back(16);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
numindices.push_back(3);
conn.push_back(2);
conn.push_back(4);
conn.push_back(15);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
numindices.push_back(3);
conn.push_back(5);
conn.push_back(6);
conn.push_back(7);
shapes.push_back(vtkm::CELL_SHAPE_QUAD);
numindices.push_back(4);
conn.push_back(0);
conn.push_back(3);
conn.push_back(5);
conn.push_back(2);
shapes.push_back(vtkm::CELL_SHAPE_QUAD);
numindices.push_back(4);
conn.push_back(5);
conn.push_back(4);
conn.push_back(10);
conn.push_back(11);
shapes.push_back(vtkm::CELL_SHAPE_POLYGON);
numindices.push_back(3);
conn.push_back(4);
conn.push_back(7);
conn.push_back(1);
shapes.push_back(vtkm::CELL_SHAPE_POLYGON);
numindices.push_back(4);
conn.push_back(1);
conn.push_back(6);
conn.push_back(7);
conn.push_back(2);
dataSet = dsb.Create(coords, shapes, numindices, conn, "coordinates", "cells");
return dataSet;
}
template <typename T>
std::vector<std::string> TestMeshQualityFilter(const vtkm::cont::DataSet& input,
const std::vector<vtkm::Float64>& expectedVals,
T filter)
{
std::vector<std::string> errors;
vtkm::cont::DataSet output;
try
{
output = filter.Execute(input);
}
catch (vtkm::cont::ErrorExecution&)
{
errors.push_back("Error occured while executing filter. Exiting...");
return errors;
}
//Test the computed metric values (for all cells) and expected metric
//values for equality.
const vtkm::Id numFields = output.GetNumberOfFields();
vtkm::cont::testing::TestEqualResult result = vtkm::cont::testing::test_equal_ArrayHandles(
vtkm::cont::make_ArrayHandle(expectedVals), output.GetField(numFields - 1).GetData());
if (!result)
result.PushMessage(std::string("Data doesn't match"));
return result.GetMessages();
}
//Either an error occurred during execution of the
//filter, or mismatches exist between the expected output
//and the computed filter output.
void CheckForErrors(const std::vector<std::string>& messages)
{
if (!messages.empty())
{
std::cout << "FAIL\n";
for (std::string m : messages)
std::cout << m << "\n";
}
else
std::cout << "SUCCESS\n";
}
int TestMeshQuality()
{
using FloatVec = std::vector<vtkm::Float64>;
using PairVec = std::vector<vtkm::Pair<vtkm::UInt8, vtkm::filter::CellMetric>>;
using StringVec = std::vector<std::string>;
using CharVec = std::vector<vtkm::UInt8>;
using QualityFilter = vtkm::filter::MeshQuality;
//Test variables
vtkm::cont::DataSet input = Make3DExplicitDataSet();
std::unique_ptr<QualityFilter> filter;
std::string metricSuffix;
StringVec fieldNames;
CharVec testedShapes;
PairVec shapeMetricPairs;
FloatVec expectedValues;
/***************************************************
* Test 1: Volume metric
***************************************************/
std::cout << "Testing MeshQuality filter: Volume metric"
<< "\n++++++++++++++++++++++++++++++++++++++++++++++++++\n";
//Assign a cell metric to compute for each different
//shape type that may exist in the input dataset. If no metric
//is specified for a shape type, then it is assumed to be EMPTY
//and no metric is computed.
testedShapes = { vtkm::CELL_SHAPE_TETRA, vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::CELL_SHAPE_WEDGE,
vtkm::CELL_SHAPE_PYRAMID, vtkm::CELL_SHAPE_POLYGON, vtkm::CELL_SHAPE_LINE,
vtkm::CELL_SHAPE_QUAD, vtkm::CELL_SHAPE_TRIANGLE };
shapeMetricPairs.clear();
for (auto s : testedShapes)
shapeMetricPairs.push_back(vtkm::make_Pair(s, vtkm::filter::CellMetric::VOLUME));
//The ground truth metric value for each cell in the input dataset.
//These values are generated from VisIt using the equivalent pseudocolor
//mesh quality metric.
expectedValues = { 1, 1, 0.0100042, 0.0983333, 0.0732667, 0.0845833, -0.5, -0.5, 0,
0, 1, 1, 1.5, 0.7071068, 2, 1, 0.5, 1 };
filter.reset(new QualityFilter(shapeMetricPairs));
std::vector<std::string> errors =
TestMeshQualityFilter<QualityFilter>(input, expectedValues, *filter);
std::cout << "Volume metric test: ";
CheckForErrors(errors);
/***************************************************
* Test 2: Edge Ratio metric
***************************************************/
std::cout << "\nTesting MeshQuality filter: Edge Ratio metric"
<< "\n++++++++++++++++++++++++++++++++++++++++++++++++++\n";
testedShapes = { vtkm::CELL_SHAPE_TETRA, vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::CELL_SHAPE_WEDGE,
vtkm::CELL_SHAPE_PYRAMID, vtkm::CELL_SHAPE_POLYGON, vtkm::CELL_SHAPE_LINE,
vtkm::CELL_SHAPE_QUAD, vtkm::CELL_SHAPE_TRIANGLE };
shapeMetricPairs.clear();
for (auto s : testedShapes)
shapeMetricPairs.push_back(vtkm::make_Pair(s, vtkm::filter::CellMetric::EDGE_RATIO));
expectedValues = { 1, 1, 2.55938, 1.80027, 2.59323, 1.73099, 1.41421, 1.41421, 0,
0, 1, 1, 2.12132, 2.44949, 2, 1, 1.41421, 1.41421 };
filter.reset(new QualityFilter(shapeMetricPairs));
errors = TestMeshQualityFilter<QualityFilter>(input, expectedValues, *filter);
std::cout << "Edge ratio metric test: ";
CheckForErrors(errors);
/***************************************************
* Test 3: Diagonal Ratio metric
***************************************************/
std::cout << "Testing MeshQuality filter: Diagonal Ratio metric"
<< "\n++++++++++++++++++++++++++++++++++++++++++++++++++\n";
testedShapes = { vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::CELL_SHAPE_POLYGON, vtkm::CELL_SHAPE_QUAD };
shapeMetricPairs.clear();
for (auto s : testedShapes)
shapeMetricPairs.push_back(vtkm::make_Pair(s, vtkm::filter::CellMetric::DIAGONAL_RATIO));
expectedValues = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2.23607 };
filter.reset(new QualityFilter(shapeMetricPairs));
errors = TestMeshQualityFilter<QualityFilter>(input, expectedValues, *filter);
std::cout << "Diagonal ratio metric test: ";
CheckForErrors(errors);
#if 0
/***************************************************
* Test 4: Oddy metric
***************************************************/
std::cout << "Testing MeshQuality filter: Oddy metric"
<< "\n++++++++++++++++++++++++++++++++++++++++++++++++++\n";
testedShapes = {vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::CELL_SHAPE_POLYGON,
vtkm::CELL_SHAPE_QUAD};
shapeMetricPairs.clear();
for (auto s : testedShapes)
shapeMetricPairs.push_back(vtkm::make_Pair(s, vtkm::filter::CellMetric::ODDY));
expectedValues = {0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1.125, 0,
0, 2.5}; /*(all cells, volume value)*/
filter.reset(new QualityFilter(shapeMetricPairs));
errors = TestMeshQualityFilter<QualityFilter>(input, expectedValues, *filter);
std::cout << "Oddy metric test: ";
CheckForErrors(errors);
/***************************************************
* Test 4: Relative Size Squared metric
***************************************************/
std::cout << "Testing MeshQuality filter: Relative Size Squared metric"
<< "\n++++++++++++++++++++++++++++++++++++++++++++++++++\n";
testedShapes = {vtkm::CELL_SHAPE_HEXAHEDRON, vtkm::CELL_SHAPE_POLYGON,
vtkm::CELL_SHAPE_QUAD, vtkm::CELL_SHAPE_TRIANGLE,
vtkm::CELL_SHAPE_TETRA};
shapeMetricPairs.clear();
for (auto s : testedShapes)
shapeMetricPairs.push_back(vtkm::make_Pair(s, vtkm::filter::CellMetric::RELATIVE_SIZE));
expectedValues = {1, 1, 0.0341086, 0.303456, 0, 0, 0,
0, 0, 0, 0, 0, 0.361898, 0.614047, 1, 1,
0.307024, 1};
filter.reset(new QualityFilter(shapeMetricPairs));
errors = TestMeshQualityFilter<QualityFilter>(input, expectedValues, *filter);
std::cout << "Relative Size Square metric test: ";
CheckForErrors(errors);
#endif
return 0;
}
int UnitTestMeshQualityFilter(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestMeshQuality, argc, argv);
}

@ -64,6 +64,8 @@ set(headers
Invocation.h
ListTagDetail.h
Unreachable.h
Variant.h
VariantDetail.h
Windows.h
)
@ -71,6 +73,7 @@ vtkm_declare_headers(${headers})
vtkm_pyexpander_generated_file(FunctionInterfaceDetailPre.h)
vtkm_pyexpander_generated_file(FunctionInterfaceDetailPost.h)
vtkm_pyexpander_generated_file(VariantDetail.h)
add_subdirectory(testing)

@ -119,6 +119,40 @@ struct ListContainsImpl
static constexpr bool value = (size::value != 0);
};
//-----------------------------------------------------------------------------
template <typename BrigandList>
struct ListSizeImpl;
template <typename... Ts>
struct ListSizeImpl<brigand::list<Ts...>>
{
static constexpr vtkm::IdComponent value = vtkm::IdComponent{ sizeof...(Ts) };
};
//-----------------------------------------------------------------------------
template <typename Type, typename RemainingList, vtkm::IdComponent NumBefore>
struct ListIndexOfImpl;
template <typename Type, vtkm::IdComponent NumBefore>
struct ListIndexOfImpl<Type, brigand::list<>, NumBefore>
{
// Could not find index.
static constexpr vtkm::IdComponent value = -1;
};
template <typename Type, typename T1, typename... RemainingList, vtkm::IdComponent NumBefore>
struct ListIndexOfImpl<Type, brigand::list<T1, RemainingList...>, NumBefore>
{
static constexpr vtkm::IdComponent value =
ListIndexOfImpl<Type, brigand::list<RemainingList...>, NumBefore + 1>::value;
};
template <typename Type, typename... RemainingList, vtkm::IdComponent NumBefore>
struct ListIndexOfImpl<Type, brigand::list<Type, RemainingList...>, NumBefore>
{
static constexpr vtkm::IdComponent value = NumBefore;
};
//-----------------------------------------------------------------------------
template <class T, class U, class ListTag>
struct intersect_tags

298
vtkm/internal/Variant.h Normal file

@ -0,0 +1,298 @@
//============================================================================
// 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_internal_Variant_h
#define vtk_m_internal_Variant_h
#include <vtkm/internal/VariantDetail.h>
#include <vtkm/ListTag.h>
namespace vtkm
{
namespace internal
{
namespace detail
{
struct VariantCopyFunctor
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename T>
VTKM_EXEC_CONT void operator()(const T& src, void* destPointer) const noexcept
{
new (destPointer) T(src);
}
};
struct VariantDestroyFunctor
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename T>
VTKM_EXEC_CONT void operator()(T& src) const noexcept
{
src.~T();
}
};
} // namespace detail
template <typename... Ts>
class Variant
{
struct ListTag : vtkm::ListTagBase<Ts...>
{
};
typename std::aligned_union<0, Ts...>::type Storage;
VTKM_EXEC_CONT void* GetPointer() { return reinterpret_cast<void*>(&this->Storage); }
VTKM_EXEC_CONT const void* GetPointer() const
{
return reinterpret_cast<const void*>(&this->Storage);
}
vtkm::IdComponent Index = -1;
public:
/// Returns the index of the type of object this variant is storing. If no object is currently
/// stored (i.e. the Variant is invalid), -1 is returned.
///
VTKM_EXEC_CONT vtkm::IdComponent GetIndex() const noexcept { return this->Index; }
/// Returns true if this Variant is storing an object from one of the types in the template
/// list, false otherwise.
///
VTKM_EXEC_CONT bool IsValid() const noexcept { return this->GetIndex() >= 0; }
/// Type that converts to a std::integral_constant containing the index of the given type (or
/// -1 if that type is not in the list).
template <typename T>
using IndexOf = std::integral_constant<vtkm::IdComponent, vtkm::ListIndexOf<ListTag, T>::value>;
/// Returns the index for the given type (or -1 if that type is not in the list).
///
template <typename T>
VTKM_EXEC_CONT static constexpr vtkm::IdComponent GetIndexOf()
{
return IndexOf<T>::value;
}
/// Type that converts to the type at the given index.
///
template <vtkm::IdComponent Index>
using TypeAt = typename vtkm::ListTypeAt<ListTag, Index>::type;
/// The number of types representable by this Variant.
///
static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) };
Variant() = default;
template <typename T>
VTKM_EXEC_CONT Variant(const T& src) noexcept
{
constexpr vtkm::IdComponent index = GetIndexOf<T>();
// Might be a way to use an enable_if to enforce a proper type.
VTKM_STATIC_ASSERT_MSG(index >= 0, "Attempting to put invalid type into a Variant");
new (this->GetPointer()) T(src);
this->Index = index;
}
template <typename T>
VTKM_EXEC_CONT Variant(const T&& src) noexcept
{
constexpr vtkm::IdComponent index = IndexOf<T>::value;
// Might be a way to use an enable_if to enforce a proper type.
VTKM_STATIC_ASSERT_MSG(index >= 0, "Attempting to put invalid type into a Variant");
new (this->GetPointer()) T(std::move(src));
this->Index = index;
}
VTKM_EXEC_CONT Variant(Variant&& rhs) noexcept
{
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
}
VTKM_EXEC_CONT Variant(const Variant& src) noexcept
{
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
this->Index = src.GetIndex();
}
VTKM_EXEC_CONT ~Variant() { this->Reset(); }
VTKM_EXEC_CONT Variant& operator=(Variant&& rhs) noexcept
{
this->Reset();
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
return *this;
}
VTKM_EXEC_CONT Variant& operator=(const Variant& src) noexcept
{
this->Reset();
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
this->Index = src.GetIndex();
return *this;
}
template <typename T, typename... Args>
VTKM_EXEC_CONT T& Emplace(Args&&... args)
{
constexpr vtkm::IdComponent I = GetIndexOf<T>();
VTKM_STATIC_ASSERT_MSG(I >= 0, "Variant::Emplace called with invalid type.");
return this->EmplaceImpl<T, I>(std::forward<Args>(args)...);
}
template <typename T, typename U, typename... Args>
VTKM_EXEC_CONT T& Emplace(std::initializer_list<U> il, Args&&... args)
{
constexpr vtkm::IdComponent I = GetIndexOf<T>();
VTKM_STATIC_ASSERT_MSG(I >= 0, "Variant::Emplace called with invalid type.");
return this->EmplaceImpl<T, I>(il, std::forward<Args>(args)...);
}
template <vtkm::IdComponent I, typename... Args>
VTKM_EXEC_CONT TypeAt<I>& Emplace(Args&&... args)
{
VTKM_STATIC_ASSERT_MSG((I >= 0) && (I < NumberOfTypes),
"Variant::Emplace called with invalid index");
return this->EmplaceImpl<TypeAt<I>, I>(std::forward<Args>(args)...);
}
template <vtkm::IdComponent I, typename U, typename... Args>
VTKM_EXEC_CONT TypeAt<I>& Emplace(std::initializer_list<U> il, Args&&... args)
{
VTKM_STATIC_ASSERT_MSG((I >= 0) && (I < NumberOfTypes),
"Variant::Emplace called with invalid index");
return this->EmplaceImpl<TypeAt<I>, I>(il, std::forward<Args>(args)...);
}
private:
template <typename T, vtkm::IdComponent I, typename... Args>
VTKM_EXEC_CONT T& EmplaceImpl(Args&&... args)
{
this->Reset();
T* value = new (this->GetPointer()) T{ args... };
this->Index = I;
return *value;
}
template <typename T, vtkm::IdComponent I, typename U, typename... Args>
VTKM_EXEC_CONT T& EmplaceImpl(std::initializer_list<U> il, Args&&... args)
{
this->Reset();
T* value = new (this->GetPointer()) T(il, args...);
this->Index = I;
return *value;
}
public:
//@{
/// Returns the value as the type at the given index. The behavior is undefined if the
/// variant does not contain the value at the given index.
///
template <vtkm::IdComponent I>
VTKM_EXEC_CONT TypeAt<I>& Get() noexcept
{
VTKM_ASSERT(I == this->GetIndex());
return *reinterpret_cast<TypeAt<I>*>(this->GetPointer());
}
template <vtkm::IdComponent I>
VTKM_EXEC_CONT const TypeAt<I>& Get() const noexcept
{
VTKM_ASSERT(I == this->GetIndex());
return *reinterpret_cast<const TypeAt<I>*>(this->GetPointer());
}
//@}
//@{
/// Returns the value as the given type. The behavior is undefined if the variant does not
/// contain a value of the given type.
///
template <typename T>
VTKM_EXEC_CONT T& Get() noexcept
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return *reinterpret_cast<T*>(this->GetPointer());
}
template <typename T>
VTKM_EXEC_CONT const T& Get() const noexcept
{
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
return *reinterpret_cast<const T*>(this->GetPointer());
}
//@}
//@{
/// Given a functor object, calls the functor with the contained object cast to the appropriate
/// type. If extra \c args are given, then those are also passed to the functor after the cast
/// object. If the functor returns a value, that value is returned from \c CastAndCall.
///
/// The results are undefined if the Variant is not valid.
///
template <typename Functor, typename... Args>
VTKM_EXEC_CONT auto CastAndCall(Functor&& f, Args&&... args) const
noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<const TypeAt<0>&>(), args...))
{
VTKM_ASSERT(this->IsValid());
return detail::VariantCastAndCallImpl<decltype(f(std::declval<const TypeAt<0>&>(), args...))>(
vtkm::internal::ListTagAsBrigandList<ListTag>(),
this->GetIndex(),
std::forward<Functor>(f),
this->GetPointer(),
std::forward<Args>(args)...);
}
template <typename Functor, typename... Args>
VTKM_EXEC_CONT auto CastAndCall(Functor&& f, Args&&... args) noexcept(
noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<TypeAt<0>&>(), args...))
{
VTKM_ASSERT(this->IsValid());
return detail::VariantCastAndCallImpl<decltype(f(std::declval<TypeAt<0>&>(), args...))>(
vtkm::internal::ListTagAsBrigandList<ListTag>(),
this->GetIndex(),
std::forward<Functor>(f),
this->GetPointer(),
std::forward<Args>(args)...);
}
/// Destroys any object the Variant is holding and sets the Variant to an invalid state. This
/// method is not thread safe.
///
VTKM_EXEC_CONT void Reset() noexcept
{
if (this->IsValid())
{
this->CastAndCall(detail::VariantDestroyFunctor{});
this->Index = -1;
}
}
};
/// \brief Convert a ListTag to a Variant.
///
template <typename ListTag>
using ListTagAsVariant = typename vtkm::ListTagApply<ListTag, vtkm::internal::Variant>::type;
}
} // namespace vtkm::internal
#endif //vtk_m_internal_Variant_h

File diff suppressed because it is too large Load Diff

@ -0,0 +1,210 @@
//============================================================================
// 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.
//============================================================================
$# This file uses the pyexpander macro processing utility to build the
$# FunctionInterface facilities that use a variable number of arguments.
$# Information, documentation, and downloads for pyexpander can be found at:
$#
$# http://pyexpander.sourceforge.net/
$#
$# To build the source code, execute the following (after installing
$# pyexpander, of course):
$#
$# expander.py VariantDetail.h.in > VariantDetail.h
$#
$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by VariantDetail.h.in
#ifndef vtk_m_internal_VariantDetail_h
#define vtk_m_internal_VariantDetail_h
#ifndef vtk_m_internal_Variant_h
#error VariantDetail.h must be included from Variant.h
#endif
#include <vtkm/Types.h>
#include <vtkm/internal/brigand.hpp>
#include <type_traits>
$py(max_expanded=20)\
$# Python commands used in template expansion.
$py(
def type_list(num_params):
if num_params < 0:
return ''
result = 'T0'
for param in range(1, num_params + 1):
result += ', T%d' % param
return result
)\
$#
$extend(type_list)\
namespace vtkm
{
namespace internal
{
namespace detail
{
template <typename ReturnType>
struct VariantDummyReturn
{
VTKM_EXEC_CONT static inline ReturnType F() noexcept { return ReturnType{}; }
};
template <>
struct VariantDummyReturn<void>
{
VTKM_EXEC_CONT static inline void F() noexcept {}
};
template <typename ReturnType, typename Functor, typename... Args>
VTKM_EXEC_CONT inline ReturnType VariantCastAndCallImpl(brigand::list<>,
vtkm::IdComponent,
Functor&&,
const void*,
Args&&...) noexcept
{
// If we are here, it means we failed to find the appropriate type in a variant
VTKM_ASSERT(false && "Internal error, bad Variant state.");
return VariantDummyReturn<ReturnType>::F();
}
// clang-format off
$for(num_params in range(0, max_expanded))\
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ReturnType,
$for(param_index in range(0, num_params + 1))\
typename T$(param_index),
$endfor\
typename Functor,
typename... Args>
VTKM_EXEC_CONT inline ReturnType VariantCastAndCallImpl(
brigand::list<$type_list(num_params)>,
vtkm::IdComponent index,
Functor&& f,
const void* storage,
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
switch (index)
{
$for(param_index in range(0, num_params + 1))\
case $(param_index):
return f(*reinterpret_cast<const T$(param_index)*>(storage), std::forward<Args>(args)...);
$endfor\
default:
// If we are here, it means we failed to find the appropriate type in a variant
VTKM_ASSERT(false && "Internal error, bad Variant state.");
return VariantDummyReturn<ReturnType>::F();
}
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ReturnType,
$for(param_index in range(0, num_params + 1))\
typename T$(param_index),
$endfor\
typename Functor,
typename... Args>
VTKM_EXEC_CONT inline ReturnType VariantCastAndCallImpl(
brigand::list<$type_list(num_params)>,
vtkm::IdComponent index,
Functor&& f,
void* storage,
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
switch (index)
{
$for(param_index in range(0, num_params + 1))\
case $(param_index):
return f(*reinterpret_cast<T$(param_index)*>(storage), std::forward<Args>(args)...);
$endfor\
default:
// If we are here, it means we failed to find the appropriate type in a variant
VTKM_ASSERT(false && "Internal error, bad Variant state.");
return VariantDummyReturn<ReturnType>::F();
}
}
$endfor\
//clang-format on
// Recurse for cases where Variant has more than $(max_expanded) types
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ReturnType,
$for(param_index in range(0, max_expanded + 1))\
typename T$(param_index),
$endfor\
typename... RemainingT,
typename Functor,
typename... Args>
VTKM_EXEC_CONT inline ReturnType VariantCastAndCallImpl(
brigand::list<$type_list(max_expanded), RemainingT...>,
vtkm::IdComponent index,
Functor&& f,
const void* storage,
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
if (index < $(max_expanded))
{
return VariantCastAndCallImpl<ReturnType>(
brigand::list<$type_list(max_expanded - 1)>{},
index,
f,
storage,
args...);
}
else
{
return VariantCastAndCallImpl<ReturnType>(
brigand::list<T$(max_expanded), RemainingT...>{}, index - $(max_expanded), f, storage, args...);
}
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ReturnType,
$for(param_index in range(0, max_expanded + 1))\
typename T$(param_index),
$endfor\
typename... RemainingT,
typename Functor,
typename... Args>
VTKM_EXEC_CONT inline ReturnType VariantCastAndCallImpl(
brigand::list<$type_list(max_expanded), RemainingT...>,
vtkm::IdComponent index,
Functor&& f,
void* storage,
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
{
if (index < $(max_expanded))
{
return VariantCastAndCallImpl<ReturnType>(
brigand::list<$type_list(max_expanded - 1)>{},
index,
f,
storage,
args...);
}
else
{
return VariantCastAndCallImpl<ReturnType>(
brigand::list<T$(max_expanded), RemainingT...>{}, index - $(max_expanded), f, storage, args...);
}
}
}
}
} // vtkm::internal::detail
#endif //vtk_m_internal_VariantDetail_h

@ -13,5 +13,6 @@ set(unit_tests
UnitTestConfigureFor32.cxx
UnitTestConfigureFor64.cxx
UnitTestFunctionInterface.cxx
UnitTestVariant.cxx
)
vtkm_unit_tests(SOURCES ${unit_tests})

@ -0,0 +1,232 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/internal/Variant.h>
#include <vtkm/testing/Testing.h>
#include <vector>
namespace
{
template <vtkm::IdComponent Index>
struct TypePlaceholder
{
};
void TestSize()
{
std::cout << "Test size" << std::endl;
using VariantType = vtkm::internal::Variant<float, double, char, short, int, long>;
constexpr size_t variantSize = sizeof(VariantType);
VTKM_TEST_ASSERT(variantSize <= 16,
"Size of variant should not be larger than biggest type plus and index. ",
variantSize);
}
void TestIndexing()
{
std::cout << "Test indexing" << std::endl;
using VariantType = vtkm::internal::
Variant<TypePlaceholder<0>, TypePlaceholder<1>, TypePlaceholder<2>, TypePlaceholder<3>>;
VariantType variant;
VTKM_TEST_ASSERT(VariantType::IndexOf<TypePlaceholder<0>>::value == 0);
VTKM_TEST_ASSERT(VariantType::IndexOf<TypePlaceholder<1>>::value == 1);
VTKM_TEST_ASSERT(VariantType::IndexOf<TypePlaceholder<2>>::value == 2);
VTKM_TEST_ASSERT(VariantType::IndexOf<TypePlaceholder<3>>::value == 3);
VTKM_TEST_ASSERT(variant.GetIndexOf<TypePlaceholder<0>>() == 0);
VTKM_TEST_ASSERT(variant.GetIndexOf<TypePlaceholder<1>>() == 1);
VTKM_TEST_ASSERT(variant.GetIndexOf<TypePlaceholder<2>>() == 2);
VTKM_TEST_ASSERT(variant.GetIndexOf<TypePlaceholder<3>>() == 3);
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<0>, TypePlaceholder<0>>::value));
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<1>, TypePlaceholder<1>>::value));
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<2>, TypePlaceholder<2>>::value));
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<3>, TypePlaceholder<3>>::value));
}
struct TestFunctor
{
template <vtkm::IdComponent Index>
vtkm::FloatDefault operator()(TypePlaceholder<Index>, vtkm::Id expectedValue)
{
VTKM_TEST_ASSERT(Index == expectedValue, "Index = ", Index, ", expected = ", expectedValue);
return TestValue(expectedValue, vtkm::FloatDefault{});
}
};
void TestGet()
{
std::cout << "Test Get" << std::endl;
using VariantType = vtkm::internal::Variant<TypePlaceholder<0>,
TypePlaceholder<1>,
vtkm::Id,
TypePlaceholder<2>,
TypePlaceholder<3>>;
const vtkm::Id expectedValue = TestValue(3, vtkm::Id{});
VariantType variant = expectedValue;
VTKM_TEST_ASSERT(variant.GetIndex() == 2);
VTKM_TEST_ASSERT(variant.Get<2>() == expectedValue);
VTKM_TEST_ASSERT(variant.Get<vtkm::Id>() == expectedValue);
}
void TestCastAndCall()
{
std::cout << "Test CastAndCall" << std::endl;
using VariantType = vtkm::internal::
Variant<TypePlaceholder<0>, TypePlaceholder<1>, TypePlaceholder<2>, TypePlaceholder<3>>;
vtkm::FloatDefault result;
VariantType variant0{ TypePlaceholder<0>{} };
result = variant0.CastAndCall(TestFunctor(), 0);
VTKM_TEST_ASSERT(test_equal(result, TestValue(0, vtkm::FloatDefault{})));
VariantType variant1{ TypePlaceholder<1>{} };
result = variant1.CastAndCall(TestFunctor(), 1);
VTKM_TEST_ASSERT(test_equal(result, TestValue(1, vtkm::FloatDefault{})));
const VariantType variant2{ TypePlaceholder<2>{} };
result = variant2.CastAndCall(TestFunctor(), 2);
VTKM_TEST_ASSERT(test_equal(result, TestValue(2, vtkm::FloatDefault{})));
VariantType variant3{ TypePlaceholder<3>{} };
result = variant3.CastAndCall(TestFunctor(), 3);
VTKM_TEST_ASSERT(test_equal(result, TestValue(3, vtkm::FloatDefault{})));
}
void TestCopyDestroy()
{
std::cout << "Test copy destroy" << std::endl;
struct CountConstructDestruct
{
vtkm::Id* Count;
CountConstructDestruct(vtkm::Id* count)
: Count(count)
{
++(*this->Count);
}
CountConstructDestruct(const CountConstructDestruct& src)
: Count(src.Count)
{
++(*this->Count);
}
~CountConstructDestruct() { --(*this->Count); }
};
using VariantType = vtkm::internal::Variant<TypePlaceholder<0>,
TypePlaceholder<1>,
CountConstructDestruct,
TypePlaceholder<2>,
TypePlaceholder<3>>;
vtkm::Id count = 0;
VariantType variant1 = CountConstructDestruct(&count);
VTKM_TEST_ASSERT(count == 1, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 1);
{
VariantType variant2{ variant1 };
VTKM_TEST_ASSERT(count == 2, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 2);
VTKM_TEST_ASSERT(*variant2.Get<2>().Count == 2);
}
VTKM_TEST_ASSERT(count == 1, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 1);
{
VariantType variant3{ VariantType(CountConstructDestruct(&count)) };
VTKM_TEST_ASSERT(count == 2, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 2);
VTKM_TEST_ASSERT(*variant3.Get<2>().Count == 2);
}
VTKM_TEST_ASSERT(count == 1, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 1);
{
VariantType variant4{ variant1 };
VTKM_TEST_ASSERT(count == 2, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 2);
VTKM_TEST_ASSERT(*variant4.Get<2>().Count == 2);
variant4 = TypePlaceholder<0>{};
VTKM_TEST_ASSERT(count == 1, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 1);
variant4 = VariantType{ TypePlaceholder<1>{} };
VTKM_TEST_ASSERT(count == 1, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 1);
variant4 = variant1;
VTKM_TEST_ASSERT(count == 2, count);
VTKM_TEST_ASSERT(*variant1.Get<2>().Count == 2);
VTKM_TEST_ASSERT(*variant4.Get<2>().Count == 2);
}
}
void TestEmplace()
{
std::cout << "Test Emplace" << std::endl;
using VariantType = vtkm::internal::Variant<vtkm::Id, vtkm::Id3, std::vector<vtkm::Id>>;
VariantType variant;
variant.Emplace<vtkm::Id>(TestValue(0, vtkm::Id{}));
VTKM_TEST_ASSERT(variant.GetIndex() == 0);
VTKM_TEST_ASSERT(variant.Get<vtkm::Id>() == TestValue(0, vtkm::Id{}));
variant.Emplace<1>(TestValue(1, vtkm::Id{}));
VTKM_TEST_ASSERT(variant.GetIndex() == 1);
VTKM_TEST_ASSERT(variant.Get<vtkm::Id3>() == vtkm::Id3{ TestValue(1, vtkm::Id{}) });
variant.Emplace<1>(TestValue(2, vtkm::Id{}), TestValue(3, vtkm::Id{}), TestValue(4, vtkm::Id{}));
VTKM_TEST_ASSERT(variant.GetIndex() == 1);
VTKM_TEST_ASSERT(variant.Get<vtkm::Id3>() == vtkm::Id3{ TestValue(2, vtkm::Id{}),
TestValue(3, vtkm::Id{}),
TestValue(4, vtkm::Id{}) });
variant.Emplace<2>(
{ TestValue(5, vtkm::Id{}), TestValue(6, vtkm::Id{}), TestValue(7, vtkm::Id{}) });
VTKM_TEST_ASSERT(variant.GetIndex() == 2);
VTKM_TEST_ASSERT(variant.Get<std::vector<vtkm::Id>>() ==
std::vector<vtkm::Id>{ TestValue(5, vtkm::Id{}),
TestValue(6, vtkm::Id{}),
TestValue(7, vtkm::Id{}) });
}
void RunTest()
{
TestSize();
TestIndexing();
TestGet();
TestCastAndCall();
TestCopyDestroy();
TestEmplace();
}
} // anonymous namespace
int UnitTestVariant(int argc, char* argv[])
{
return vtkm::testing::Testing::Run(RunTest, argc, argv);
}

@ -490,8 +490,16 @@ private:
void OpenFile()
{
this->DataFile->Stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
std::ios_base::in | std::ios_base::binary);
try
{
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
std::ios_base::in | std::ios_base::binary);
}
catch (std::ifstream::failure&)
{
std::string message("could not open file \"" + this->DataFile->FileName + "\"");
throw vtkm::io::ErrorIO(message);
}
}
void ReadHeader()

@ -178,7 +178,7 @@ vtkm_library(
NAME vtkm_rendering
SOURCES ${sources}
HEADERS ${headers}
WRAP_FOR_CUDA ${device_sources}
DEVICE_SOURCES ${device_sources}
)
# Install all headers no matter what backend was selected

@ -30,6 +30,7 @@ vtkm::UInt32 DecodePNG(std::vector<unsigned char>& out_image,
const unsigned char* in_png,
std::size_t in_size)
{
using namespace vtkm::png;
constexpr std::size_t bitdepth = 8;
vtkm::UInt32 iw = 0;
vtkm::UInt32 ih = 0;

@ -45,4 +45,4 @@ set(unit_tests
UnitTestVecVariable.cxx
)
VTKM_unit_tests(SOURCES ${unit_tests})
vtkm_unit_tests(SOURCES ${unit_tests})

@ -120,7 +120,8 @@ void CheckContains(TestClass<N>, ListTag, const std::vector<int>& contents)
{
//Use intersect to verify at compile time that ListTag contains TestClass<N>
using intersectWith = vtkm::ListTagBase<TestClass<N>>;
using intersectResult = typename vtkm::ListTagIntersect<intersectWith, ListTag>::list;
using intersectResult =
vtkm::internal::ListTagAsBrigandList<vtkm::ListTagIntersect<intersectWith, ListTag>>;
constexpr bool intersectContains = (brigand::size<intersectResult>::value != 0);
bool listContains = vtkm::ListContains<ListTag, TestClass<N>>::value;
@ -135,8 +136,8 @@ void CheckContains(TestClass<N>, TestListTagUniversal, const std::vector<int>&)
{
//Use intersect to verify at compile time that ListTag contains TestClass<N>
using intersectWith = vtkm::ListTagBase<TestClass<N>>;
using intersectResult =
typename vtkm::ListTagIntersect<intersectWith, TestListTagUniversal>::list;
using intersectResult = vtkm::internal::ListTagAsBrigandList<
vtkm::ListTagIntersect<intersectWith, TestListTagUniversal>>;
constexpr bool intersectContains = (brigand::size<intersectResult>::value != 0);
constexpr bool listContains = vtkm::ListContains<TestListTagUniversal, TestClass<N>>::value;
@ -148,6 +149,8 @@ void TryList(const vtkm::Vec<int, N>& expected, ListTag)
{
VTKM_IS_LIST_TAG(ListTag);
VTKM_STATIC_ASSERT(vtkm::ListSize<ListTag>::value == N);
std::cout << " Try mutable for each" << std::endl;
MutableFunctor<int> functor;
vtkm::ListForEach(functor, ListTag());

@ -39,6 +39,11 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
#endif /*_MSC_VER */
namespace vtkm
{
namespace png
{
const char* LODEPNG_VERSION_STRING = "20190615";
/*
@ -5975,3 +5980,6 @@ unsigned encode(const std::string& filename,
#endif /* LODEPNG_COMPILE_PNG */
} /* namespace lodepng */
#endif /*LODEPNG_COMPILE_CPP*/
} /* namespace png */
} /* namespace vtkm */

@ -28,6 +28,11 @@ freely, subject to the following restrictions:
#include <string.h> /*for size_t*/
namespace vtkm
{
namespace png
{
extern const char* LODEPNG_VERSION_STRING;
/*
@ -1035,6 +1040,9 @@ unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned ch
} /* namespace lodepng */
#endif /*LODEPNG_COMPILE_CPP*/
} /* namespace png */
} /* namespace vtkm */
/*
TODO:
[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often

@ -44,6 +44,7 @@ set(headers
MaskNone.h
MaskPoints.h
MaskSelect.h
MeshQuality.h
NDimsEntropy.h
NDimsHistMarginalization.h
NDimsHistogram.h
@ -65,6 +66,7 @@ set(headers
SplitSharpEdges.h
StableSortIndices.h
StreamLineUniformGrid.h
StreamSurface.h
SurfaceNormals.h
Tetrahedralize.h
Threshold.h
@ -132,7 +134,7 @@ vtkm_library(
SOURCES ${sources_no_device}
TEMPLATE_SOURCES ${header_impls}
HEADERS ${headers}
WRAP_FOR_CUDA ${sources_device}
DEVICE_SOURCES ${sources_device}
)
target_link_libraries(vtkm_worklet PUBLIC vtkm_cont)

130
vtkm/worklet/MeshQuality.h Normal file

@ -0,0 +1,130 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2018 UT-Battelle, LLC.
// Copyright 2018 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_MeshQuality_h
#define vtk_m_worklet_MeshQuality_h
#include "vtkm/exec/CellMeasure.h"
#include "vtkm/exec/cellmetrics/CellDiagonalRatioMetric.h"
#include "vtkm/exec/cellmetrics/CellEdgeRatioMetric.h"
#include "vtkm/worklet/WorkletMapTopology.h"
namespace vtkm
{
namespace worklet
{
/**
* Worklet that computes mesh quality metric values for each cell in
* the input mesh. A metric is specified per cell type in the calling filter,
* and this metric is invoked over all cells of that cell type. An array of
* the computed metric values (one per cell) is returned as output.
*/
template <typename MetricTagType>
class MeshQuality : public vtkm::worklet::WorkletMapPointToCell
{
public:
using ControlSignature = void(CellSetIn cellset,
WholeArrayIn counts,
WholeArrayIn metrics,
FieldInPoint pointCoords,
FieldOutCell metricOut);
using ExecutionSignature = void(CellShape, PointCount, _2, _3, _4, _5);
using InputDomain = _1;
template <typename CellShapeType,
typename PointCoordVecType,
typename CountsArrayType,
typename MetricsArrayType,
typename OutType>
VTKM_EXEC void operator()(CellShapeType shape,
const vtkm::IdComponent& numPoints,
const CountsArrayType& counts,
const MetricsArrayType& metrics,
const PointCoordVecType& pts,
OutType& metricValue) const
{
printf("shape.Id: %u\n", shape.Id);
vtkm::UInt8 thisId = shape.Id;
if (shape.Id == vtkm::CELL_SHAPE_POLYGON)
{
if (numPoints == 3)
thisId = vtkm::CELL_SHAPE_TRIANGLE;
else if (numPoints == 4)
thisId = vtkm::CELL_SHAPE_QUAD;
}
switch (thisId)
{
vtkmGenericCellShapeMacro(
metricValue = this->ComputeMetric<OutType>(
numPoints, pts, counts.Get(shape.Id), CellShapeTag(), metrics.Get(CellShapeTag().Id)));
default:
this->RaiseError("Asked for metric of unknown cell type.");
metricValue = OutType(0.0);
}
}
protected:
template <typename OutType,
typename PointCoordVecType,
typename CellShapeType,
typename CellMetricType>
VTKM_EXEC OutType ComputeMetric(const vtkm::IdComponent& numPts,
const PointCoordVecType& pts,
const vtkm::Id& numShapes,
CellShapeType tag,
CellMetricType metric) const
{
UNUSED(numShapes);
constexpr vtkm::IdComponent dims = vtkm::CellTraits<CellShapeType>::TOPOLOGICAL_DIMENSIONS;
//Only compute the metric for 2D and 3D shapes; return 0 otherwise
OutType metricValue = OutType(0.0);
if (dims > 0)
{
switch (metric)
{
case MetricTagType::DIAGONAL_RATIO:
metricValue =
vtkm::exec::cellmetrics::CellDiagonalRatioMetric<OutType>(numPts, pts, tag, *this);
break;
case MetricTagType::EDGE_RATIO:
metricValue =
vtkm::exec::cellmetrics::CellEdgeRatioMetric<OutType>(numPts, pts, tag, *this);
break;
case MetricTagType::VOLUME:
metricValue = vtkm::exec::CellMeasure<OutType>(numPts, pts, tag, *this);
break;
case MetricTagType::EMPTY:
break;
default:
//Only call metric function if a metric is specified for this shape type
this->RaiseError("Asked for unknown metric.");
}
}
return metricValue;
}
};
} // namespace worklet
} // namespace vtkm
#endif // vtk_m_worklet_MeshQuality_h

@ -0,0 +1,282 @@
//============================================================================
// 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_worklet_streamsurface_h
#define vtk_m_worklet_streamsurface_h
#include <typeinfo>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
namespace vtkm
{
namespace worklet
{
class StreamSurface
{
public:
//Helper worklet to count various things in each polyline.
class CountPolylines : public vtkm::worklet::WorkletMapPointToCell
{
public:
VTKM_CONT
CountPolylines() {}
using ControlSignature = void(CellSetIn, WholeArrayInOut invalidCell, FieldOut ptsPerPolyline);
using ExecutionSignature = void(CellShape shapeType,
PointCount numPoints,
_2 isValid,
_3 ptsPerPolyline);
using InputDomain = _1;
template <typename CellShapeTag, typename InValidType>
VTKM_EXEC void operator()(const CellShapeTag& shapeType,
const vtkm::IdComponent& numPoints,
InValidType& invalidCell,
vtkm::Id& ptsPerPolyline) const
{
// We only support polylines that contain 2 or more points.
if (shapeType.Id == vtkm::CELL_SHAPE_POLY_LINE && numPoints > 1)
ptsPerPolyline = numPoints;
else
{
invalidCell.Set(0, 1);
ptsPerPolyline = 0;
}
}
private:
};
//Helper worklet to determine number of triangles for each pair of polylines
class CountTriangleConn : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
CountTriangleConn() {}
using ControlSignature = void(FieldIn numPts0, FieldIn numPts1, FieldOut outConnCount);
using ExecutionSignature = void(_1 numPts0, _2 numPts1, _3 outConnCount);
using InputDomain = _1;
VTKM_EXEC void operator()(const vtkm::Id& numPts0,
const vtkm::Id& numPts1,
vtkm::Id& outConnCount) const
{
if (numPts0 == numPts1)
outConnCount = (numPts0 - 1) * 2 * 3;
else if (numPts1 < numPts0)
outConnCount = (numPts0 - 1) * 2 * 3 + (numPts1 - numPts0) * 3;
else
outConnCount = (numPts1 - 1) * 2 * 3 + (numPts0 - numPts1) * 3;
}
private:
};
//Helper worklet to generate the stream surface cells
class GenerateCells : public vtkm::worklet::WorkletMapField
{
public:
VTKM_CONT
GenerateCells() {}
using ControlSignature = void(FieldIn numPts0,
FieldIn numPts1,
FieldIn offset0,
FieldIn offset1,
FieldIn connOffset,
WholeArrayOut outConn);
using ExecutionSignature =
void(_1 numPts0, _2 numPts1, _3 ptOffset0, _4 offset1, _5 connOffset, _6 outConn);
using InputDomain = _1;
template <typename OutConnType>
VTKM_EXEC void operator()(const vtkm::Id& numPts0,
const vtkm::Id& numPts1,
const vtkm::Id& offset0,
const vtkm::Id& offset1,
const vtkm::Id& connOffset,
OutConnType& outConn) const
{
vtkm::Id idx0 = 0, idx1 = 0;
vtkm::Id nextToLastIdx0 = numPts0 - 1;
vtkm::Id nextToLastIdx1 = numPts1 - 1;
vtkm::Id outIdx = connOffset;
//There could be different numbers of points in the pairs of polylines.
//Create pairs of triangles as far as possible.
/* polyline0 polyline1
*
* idx0 + 1 x----------- x idx1 + 1
* | \ |
* | \ Tri2 |
* | \ |
* | \ |
* | Tri1 \ |
* | \|
* idx0 + 0 x ---------- x idx1 + 0
*
*/
while (idx0 < nextToLastIdx0 && idx1 < nextToLastIdx1)
{
//Tri 1
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
outConn.Set(outIdx + 2, offset0 + idx0 + 1);
//Tri 2
outConn.Set(outIdx + 3, offset0 + idx0 + 1);
outConn.Set(outIdx + 4, offset1 + idx1 + 0);
outConn.Set(outIdx + 5, offset1 + idx1 + 1);
idx0++;
idx1++;
outIdx += 6;
}
// Same number of points in both polylines. We are done.
if (numPts0 == numPts1)
return;
//If we have more points in one polyline, create a triangle fan
//to complete the triangulation.
//polyline0 is at the end, polyline1 still has more points.
/* polyline0 polyline1
*
* x idx1 + 1
* /|
* / |
* / |
* / |
* / Tri |
* / |
* idx0 + 0 x ---------- x idx1 + 0
*
*/
if (idx0 == nextToLastIdx0 && idx1 < nextToLastIdx1)
{
while (idx1 < nextToLastIdx1)
{
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
outConn.Set(outIdx + 2, offset1 + idx1 + 1);
idx1++;
outIdx += 3;
}
}
//polyline1 is at the end, polyline0 still has more points.
/* polyline0 polyline1
*
* idx0 + 1 x
* | \
* | \
* | \
* | \
* | Tri \
* | \
* idx0 + 0 x ---------- x idx1 + 0
*
*/
else
{
while (idx0 < nextToLastIdx0)
{
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
outConn.Set(outIdx + 2, offset0 + idx0 + 1);
idx0++;
outIdx += 3;
}
}
}
private:
};
VTKM_CONT
StreamSurface() {}
VTKM_CONT
void Run(const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::DynamicCellSet& cellset,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>>& newPoints,
vtkm::cont::CellSetSingleType<>& newCells)
{
using ExplCoordsType = vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>>;
if (!(coords.GetData().IsType<ExplCoordsType>() &&
(cellset.IsSameType(vtkm::cont::CellSetExplicit<>()) ||
cellset.IsSameType(vtkm::cont::CellSetSingleType<>()))))
{
throw vtkm::cont::ErrorBadValue("Stream surface requires polyline data.");
}
//Count number of polylines and make sure we ONLY have polylines
vtkm::cont::ArrayHandle<vtkm::Id> ptsPerPolyline, invalidCell;
vtkm::worklet::DispatcherMapTopology<CountPolylines> countInvoker;
//We only care if there are ANY non-polyline cells. So use a one element array.
//Any non-polyline cell will set the value to 1. No need to worry about race conditions
//as the outcasts will all set it to the same value.
invalidCell.Allocate(1);
invalidCell.GetPortalControl().Set(0, 0);
countInvoker.Invoke(cellset, invalidCell, ptsPerPolyline);
if (invalidCell.GetPortalConstControl().Get(0) == 1)
throw vtkm::cont::ErrorBadValue("Stream surface requires only polyline data.");
vtkm::Id numPolylines = cellset.GetNumberOfCells();
//Compute polyline offsets
vtkm::cont::ArrayHandle<vtkm::Id> polylineOffset;
vtkm::cont::Algorithm::ScanExclusive(ptsPerPolyline, polylineOffset);
auto ptsPerPolyline0 = vtkm::cont::make_ArrayHandleView(ptsPerPolyline, 0, numPolylines - 1);
auto ptsPerPolyline1 = vtkm::cont::make_ArrayHandleView(ptsPerPolyline, 1, numPolylines - 1);
//Count the number of triangles to be generated
vtkm::cont::ArrayHandle<vtkm::Id> triangleConnCount, triangleConnOffset;
vtkm::worklet::DispatcherMapField<CountTriangleConn> countTriInvoker;
countTriInvoker.Invoke(ptsPerPolyline0, ptsPerPolyline1, triangleConnCount);
vtkm::cont::Algorithm::ScanExclusive(triangleConnCount, triangleConnOffset);
//Surface points are same as input points.
newPoints = coords.GetData().Cast<ExplCoordsType>();
//Create surface triangles
vtkm::Id numConnIds = vtkm::cont::Algorithm::Reduce(triangleConnCount, vtkm::Id(0));
vtkm::cont::ArrayHandle<vtkm::Id> newConnectivity;
newConnectivity.Allocate(numConnIds);
vtkm::worklet::DispatcherMapField<GenerateCells> genCellsDisp;
genCellsDisp.Invoke(ptsPerPolyline0,
ptsPerPolyline1,
vtkm::cont::make_ArrayHandleView(polylineOffset, 0, numPolylines - 1),
vtkm::cont::make_ArrayHandleView(polylineOffset, 1, numPolylines - 1),
triangleConnOffset,
newConnectivity);
newCells.Fill(numConnIds, vtkm::CELL_SHAPE_TRIANGLE, 3, newConnectivity);
}
private:
};
}
}
#endif // vtk_m_worklet_streamsurface_h

@ -57,9 +57,9 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood
T deta = inputField.Get(0, 1, 0) - inputField.Get(0, -1, 0);
T dzeta = inputField.Get(0, 0, 1) - inputField.Get(0, 0, -1);
dxi = (boundary.InXBoundary(1) ? dxi * 0.5f : dxi);
deta = (boundary.InYBoundary(1) ? deta * 0.5f : deta);
dzeta = (boundary.InZBoundary(1) ? dzeta * 0.5f : dzeta);
dxi = (boundary.IsRadiusInXBoundary(1) ? dxi * 0.5f : dxi);
deta = (boundary.IsRadiusInYBoundary(1) ? deta * 0.5f : deta);
dzeta = (boundary.IsRadiusInZBoundary(1) ? dzeta * 0.5f : dzeta);
outputGradient[0] = static_cast<OT>(xi[0] * dxi + eta[0] * deta + zeta[0] * dzeta);
outputGradient[1] = static_cast<OT>(xi[1] * dxi + eta[1] * deta + zeta[1] * dzeta);
@ -84,9 +84,9 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood
CoordType r = inputPoints.Portal.GetSpacing();
r[0] = (boundary.InXBoundary(1) ? r[0] * 0.5f : r[0]);
r[1] = (boundary.InYBoundary(1) ? r[1] * 0.5f : r[1]);
r[2] = (boundary.InZBoundary(1) ? r[2] * 0.5f : r[2]);
r[0] = (boundary.IsRadiusInXBoundary(1) ? r[0] * 0.5f : r[0]);
r[1] = (boundary.IsRadiusInYBoundary(1) ? r[1] * 0.5f : r[1]);
r[2] = (boundary.IsRadiusInZBoundary(1) ? r[2] * 0.5f : r[2]);
const T dx = inputField.Get(1, 0, 0) - inputField.Get(-1, 0, 0);
const T dy = inputField.Get(0, 1, 0) - inputField.Get(0, -1, 0);
@ -113,9 +113,9 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood
CoordType eta = inputPoints.Get(0, 1, 0) - inputPoints.Get(0, -1, 0);
CoordType zeta = inputPoints.Get(0, 0, 1) - inputPoints.Get(0, 0, -1);
xi = (boundary.InXBoundary(1) ? xi * 0.5f : xi);
eta = (boundary.InYBoundary(1) ? eta * 0.5f : eta);
zeta = (boundary.InZBoundary(1) ? zeta * 0.5f : zeta);
xi = (boundary.IsRadiusInXBoundary(1) ? xi * 0.5f : xi);
eta = (boundary.IsRadiusInYBoundary(1) ? eta * 0.5f : eta);
zeta = (boundary.IsRadiusInZBoundary(1) ? zeta * 0.5f : zeta);
CT aj = xi[0] * eta[1] * zeta[2] + xi[1] * eta[2] * zeta[0] + xi[2] * eta[0] * zeta[1] -
xi[2] * eta[1] * zeta[0] - xi[1] * eta[0] * zeta[2] - xi[0] * eta[2] * zeta[1];

@ -59,6 +59,7 @@ set(unit_tests
UnitTestSplitSharpEdges.cxx
UnitTestStreamingSine.cxx
UnitTestStreamLineUniformGrid.cxx
UnitTestStreamSurface.cxx
UnitTestSurfaceNormals.cxx
UnitTestTemporalAdvection.cxx
UnitTestTetrahedralize.cxx

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