mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Merge branch 'master' of https://gitlab.kitware.com/vtk/vtk-m into 2DLocators
This commit is contained in:
commit
cb01e982c4
@ -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()
|
||||
|
203
CMake/testing/VTKmTestWrappers.cmake
Normal file
203
CMake/testing/VTKmTestWrappers.cmake
Normal file
@ -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)
|
||||
|
145
docs/changelog/BoundaryState-refactor.md
Normal file
145
docs/changelog/BoundaryState-refactor.md
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
224
docs/changelog/array-handle-multiplexer.md
Normal file
224
docs/changelog/array-handle-multiplexer.md
Normal file
@ -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);
|
||||
}
|
||||
|
||||
```
|
||||
|
12
docs/changelog/write-to-array-handle-cast.md
Normal file
12
docs/changelog/write-to-array-handle-cast.md
Normal file
@ -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)
|
||||
|
37
examples/mesh_quality/CMakeLists.txt
Normal file
37
examples/mesh_quality/CMakeLists.txt
Normal file
@ -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()
|
286
examples/mesh_quality/MeshQuality.cxx
Normal file
286
examples/mesh_quality/MeshQuality.cxx
Normal file
@ -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()
|
||||
|
||||
|
130
vtkm/ListTag.h
130
vtkm/ListTag.h
@ -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>>>
|
||||
{
|
||||
};
|
||||
|
||||
|
631
vtkm/cont/ArrayHandleMultiplexer.h
Normal file
631
vtkm/cont/ArrayHandleMultiplexer.h
Normal file
@ -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
|
||||
|
20
vtkm/cont/cuda/testing/UnitTestCudaArrayHandleMultiplexer.cu
Normal file
20
vtkm/cont/cuda/testing/UnitTestCudaArrayHandleMultiplexer.cu
Normal file
@ -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
|
||||
|
20
vtkm/cont/tbb/testing/UnitTestTBBArrayHandleMultiplexer.cxx
Normal file
20
vtkm/cont/tbb/testing/UnitTestTBBArrayHandleMultiplexer.cxx
Normal file
@ -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
|
||||
|
158
vtkm/cont/testing/TestingArrayHandleMultiplexer.h
Normal file
158
vtkm/cont/testing/TestingArrayHandleMultiplexer.h
Normal file
@ -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);
|
||||
|
28
vtkm/exec/cellmetrics/CMakeLists.txt
Normal file
28
vtkm/exec/cellmetrics/CMakeLists.txt
Normal file
@ -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})
|
236
vtkm/exec/cellmetrics/CellDiagonalRatioMetric.h
Normal file
236
vtkm/exec/cellmetrics/CellDiagonalRatioMetric.h
Normal file
@ -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
|
299
vtkm/exec/cellmetrics/CellEdgeRatioMetric.h
Normal file
299
vtkm/exec/cellmetrics/CellEdgeRatioMetric.h
Normal file
@ -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
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
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
|
||||
|
376
vtkm/filter/testing/UnitTestMeshQualityFilter.cxx
Normal file
376
vtkm/filter/testing/UnitTestMeshQualityFilter.cxx
Normal file
@ -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
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
|
2225
vtkm/internal/VariantDetail.h
Normal file
2225
vtkm/internal/VariantDetail.h
Normal file
File diff suppressed because it is too large
Load Diff
210
vtkm/internal/VariantDetail.h.in
Normal file
210
vtkm/internal/VariantDetail.h.in
Normal file
@ -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})
|
||||
|
232
vtkm/internal/testing/UnitTestVariant.cxx
Normal file
232
vtkm/internal/testing/UnitTestVariant.cxx
Normal file
@ -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
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
|
282
vtkm/worklet/StreamSurface.h
Normal file
282
vtkm/worklet/StreamSurface.h
Normal file
@ -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
Loading…
Reference in New Issue
Block a user