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

This commit is contained in:
dpugmire 2019-12-04 11:59:14 -05:00
commit bdab4a56d2
363 changed files with 17986 additions and 19319 deletions

1
.gitattributes vendored

@ -17,3 +17,4 @@ data/** filter=lfs diff=lfs merge=lfs -text
vtkm/thirdparty/diy/vtkmdiy/** -format.clang-format -whitespace
vtkm/thirdparty/optionparser/vtkmoptionparser/** -format.clang-format -whitespace
vtkm/thirdparty/lodepng/vtkmlodepng/** -format.clang-format -whitespace
vtkm/thirdparty/lcl/vtkmlcl/** -format.clang-format -whitespace

@ -1,539 +0,0 @@
##============================================================================
## 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.
##============================================================================
#.rst:
# FindOpenMP
# ----------
#
# Finds OpenMP support
#
# This module can be used to detect OpenMP support in a compiler. If
# the compiler supports OpenMP, the flags required to compile with
# OpenMP support are returned in variables for the different languages.
# The variables may be empty if the compiler does not need a special
# flag to support OpenMP.
#
# Variables
# ^^^^^^^^^
#
# The module exposes the components ``C``, ``CXX``, and ``Fortran``.
# Each of these controls the various languages to search OpenMP support for.
#
# Depending on the enabled components the following variables will be set:
#
# ``OpenMP_FOUND``
# Variable indicating that OpenMP flags for all requested languages have been found.
# If no components are specified, this is true if OpenMP settings for all enabled languages
# were detected.
# ``OpenMP_VERSION``
# Minimal version of the OpenMP standard detected among the requested languages,
# or all enabled languages if no components were specified.
#
# This module will set the following variables per language in your
# project, where ``<lang>`` is one of C, CXX, or Fortran:
#
# ``OpenMP_<lang>_FOUND``
# Variable indicating if OpenMP support for ``<lang>`` was detected.
# ``OpenMP_<lang>_FLAGS``
# OpenMP compiler flags for ``<lang>``, separated by spaces.
#
# For linking with OpenMP code written in ``<lang>``, the following
# variables are provided:
#
# ``OpenMP_<lang>_LIB_NAMES``
# :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``.
# ``OpenMP_<libname>_LIBRARY``
# Location of the individual libraries needed for OpenMP support in ``<lang>``.
# ``OpenMP_<lang>_LIBRARIES``
# A list of libraries needed to link with OpenMP code written in ``<lang>``.
#
# Additionally, the module provides :prop_tgt:`IMPORTED` targets:
#
# ``OpenMP::OpenMP_<lang>``
# Target for using OpenMP from ``<lang>``.
#
# Specifically for Fortran, the module sets the following variables:
#
# ``OpenMP_Fortran_HAVE_OMPLIB_HEADER``
# Boolean indicating if OpenMP is accessible through ``omp_lib.h``.
# ``OpenMP_Fortran_HAVE_OMPLIB_MODULE``
# Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module.
#
# The module will also try to provide the OpenMP version variables:
#
# ``OpenMP_<lang>_SPEC_DATE``
# Date of the OpenMP specification implemented by the ``<lang>`` compiler.
# ``OpenMP_<lang>_VERSION_MAJOR``
# Major version of OpenMP implemented by the ``<lang>`` compiler.
# ``OpenMP_<lang>_VERSION_MINOR``
# Minor version of OpenMP implemented by the ``<lang>`` compiler.
# ``OpenMP_<lang>_VERSION``
# OpenMP version implemented by the ``<lang>`` compiler.
#
# The specification date is formatted as given in the OpenMP standard:
# ``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
# the OpenMP specification implemented by the ``<lang>`` compiler.
cmake_policy(PUSH)
cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans
cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
cmake_policy(SET CMP0057 NEW) # if IN_LIST
function(_OPENMP_FLAG_CANDIDATES LANG)
if(NOT OpenMP_${LANG}_FLAG)
unset(OpenMP_FLAG_CANDIDATES)
set(OMP_FLAG_GNU "-fopenmp")
set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp")
set(OMP_FLAG_AppleClang "-Xclang -fopenmp")
set(OMP_FLAG_HP "+Oopenmp")
if(WIN32)
set(OMP_FLAG_Intel "-Qopenmp")
elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND
"${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528")
set(OMP_FLAG_Intel "-openmp")
else()
set(OMP_FLAG_Intel "-qopenmp")
endif()
set(OMP_FLAG_MIPSpro "-mp")
set(OMP_FLAG_MSVC "-openmp")
set(OMP_FLAG_PathScale "-openmp")
set(OMP_FLAG_NAG "-openmp")
set(OMP_FLAG_Absoft "-openmp")
set(OMP_FLAG_PGI "-mp")
set(OMP_FLAG_Flang "-fopenmp")
set(OMP_FLAG_SunPro "-xopenmp")
set(OMP_FLAG_XL "-qsmp=omp")
# Cray compiler activate OpenMP with -h omp, which is enabled by default.
set(OMP_FLAG_Cray " " "-h omp")
# If we know the correct flags, use those
if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}")
# Fall back to reasonable default tries otherwise
else()
set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ")
endif()
set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE)
else()
set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE)
endif()
endfunction()
# sample openmp source code to test
set(OpenMP_C_CXX_TEST_SOURCE
"
#include <omp.h>
int main() {
#ifdef _OPENMP
int n = omp_get_max_threads();
return 0;
#else
breaks_on_purpose
#endif
}
")
# in Fortran, an implementation may provide an omp_lib.h header
# or omp_lib module, or both (OpenMP standard, section 3.1)
# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2)
# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code
# while not actually enabling OpenMP, building code sequentially
set(OpenMP_Fortran_TEST_SOURCE
"
program test
@OpenMP_Fortran_INCLUDE_LINE@
!$ integer :: n
n = omp_get_num_threads()
end program test
"
)
function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP)
if("${LANG}" STREQUAL "C")
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
elseif("${LANG}" STREQUAL "CXX")
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
elseif("${LANG}" STREQUAL "Fortran")
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90")
file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}")
configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
endif()
set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
endfunction()
include(CMakeParseImplicitLinkInfo)
function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
_OPENMP_FLAG_CANDIDATES("${LANG}")
_OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC)
unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
separate_arguments(OpenMP_VERBOSE_OPTIONS NATIVE_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS)
if(NOT _VERBOSE_OPTION MATCHES "^-Wl,")
list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION})
endif()
endforeach()
foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES)
set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}")
if(OpenMP_VERBOSE_COMPILE_OPTIONS)
string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
endif()
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
)
if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
if(CMAKE_${LANG}_VERBOSE_FLAG)
unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES)
unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS)
unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS)
unset(OpenMP_${LANG}_LOG_VAR)
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}"
OpenMP_${LANG}_IMPLICIT_LIBRARIES
OpenMP_${LANG}_IMPLICIT_LINK_DIRS
OpenMP_${LANG}_IMPLICIT_FWK_DIRS
OpenMP_${LANG}_LOG_VAR
"${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}"
)
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n")
unset(_OPENMP_LIB_NAMES)
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
if(_OPENMP_IMPLICIT_LIB_DIR)
set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
"Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
else()
find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
CMAKE_FIND_ROOT_PATH_BOTH
NO_DEFAULT_PATH
)
endif()
mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
endif()
endforeach()
set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
else()
# We do not know how to extract implicit OpenMP libraries for this compiler.
# Assume that it handles them automatically, e.g. the Intel Compiler on
# Windows should put the dependency in its object files.
set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE)
endif()
break()
elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang"
AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0")
# Check for separate OpenMP library on AppleClang 7+
find_library(OpenMP_libomp_LIBRARY
NAMES omp gomp iomp5
HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
)
mark_as_advanced(OpenMP_libomp_LIBRARY)
if(OpenMP_libomp_LIBRARY)
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
)
if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
break()
endif()
endif()
endif()
set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE)
set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE)
endforeach()
unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
endfunction()
set(OpenMP_C_CXX_CHECK_VERSION_SOURCE
"
#include <stdio.h>
#include <omp.h>
const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M',
'P', '-', 'd', 'a', 't', 'e', '[',
('0' + ((_OPENMP/100000)%10)),
('0' + ((_OPENMP/10000)%10)),
('0' + ((_OPENMP/1000)%10)),
('0' + ((_OPENMP/100)%10)),
('0' + ((_OPENMP/10)%10)),
('0' + ((_OPENMP/1)%10)),
']', '\\0' };
int main()
{
puts(ompver_str);
return 0;
}
")
set(OpenMP_Fortran_CHECK_VERSION_SOURCE
"
program omp_ver
@OpenMP_Fortran_INCLUDE_LINE@
integer, parameter :: zero = ichar('0')
integer, parameter :: ompv = openmp_version
character, dimension(24), parameter :: ompver_str =&
(/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',&
'd', 'a', 't', 'e', '[',&
char(zero + mod(ompv/100000, 10)),&
char(zero + mod(ompv/10000, 10)),&
char(zero + mod(ompv/1000, 10)),&
char(zero + mod(ompv/100, 10)),&
char(zero + mod(ompv/10, 10)),&
char(zero + mod(ompv/1, 10)), ']' /)
print *, ompver_str
end program omp_ver
")
function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
_OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC)
set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin")
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}"
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}"
COPY_FILE ${BIN_FILE})
if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}})
file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date")
set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*")
if("${specstr}" MATCHES "${regex_spec_date}")
set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
endif()
endif()
endfunction()
macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
set(OpenMP_SPEC_DATE_MAP
# Preview versions
"201611=5.0" # OpenMP 5.0 preview 1
# Combined versions, 2.5 onwards
"201511=4.5"
"201307=4.0"
"201107=3.1"
"200805=3.0"
"200505=2.5"
# C/C++ version 2.0
"200203=2.0"
# Fortran version 2.0
"200011=2.0"
# Fortran version 1.1
"199911=1.1"
# C/C++ version 1.0 (there's no 1.1 for C/C++)
"199810=1.0"
# Fortran version 1.0
"199710=1.0"
)
if(OpenMP_${LANG}_SPEC_DATE)
string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
else()
set(_version_match "")
endif()
if(NOT _version_match STREQUAL "")
set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}")
else()
unset(OpenMP_${LANG}_VERSION_MAJOR)
unset(OpenMP_${LANG}_VERSION_MINOR)
unset(OpenMP_${LANG}_VERSION)
endif()
unset(_version_match)
unset(OpenMP_SPEC_DATE_MAP)
endmacro()
foreach(LANG IN ITEMS C CXX)
if(CMAKE_${LANG}_COMPILER_LOADED)
if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
_OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
endif()
set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
CACHE STRING "${LANG} compiler flags for OpenMP parallelization")
set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
CACHE STRING "${LANG} compiler libraries for OpenMP parallelization")
mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
endif()
endforeach()
if(CMAKE_Fortran_COMPILER_LOADED)
if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
_OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
if(OpenMP_Fortran_FLAGS_WORK)
set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "")
endif()
set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
CACHE STRING "Fortran compiler flags for OpenMP parallelization")
set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES)
endif()
if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
_OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
if(OpenMP_Fortran_FLAGS_WORK)
set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "")
endif()
set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
CACHE STRING "Fortran compiler flags for OpenMP parallelization")
set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}"
CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
endif()
if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
else()
set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
endif()
endif()
if(NOT OpenMP_FIND_COMPONENTS)
set(OpenMP_FINDLIST C CXX Fortran)
else()
set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
endif()
unset(_OpenMP_MIN_VERSION)
include(FindPackageHandleStandardArgs)
foreach(LANG IN LISTS OpenMP_FINDLIST)
if(CMAKE_${LANG}_COMPILER_LOADED)
if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS)
_OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL)
set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE
INTERNAL "${LANG} compiler's OpenMP specification date")
_OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}")
endif()
set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY})
set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED})
set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION})
set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT})
set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS)
if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES)
else()
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
endforeach()
endif()
find_package_handle_standard_args(OpenMP_${LANG}
REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
VERSION_VAR OpenMP_${LANG}_VERSION
)
if(OpenMP_${LANG}_FOUND)
if(DEFINED OpenMP_${LANG}_VERSION)
if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION)
set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION)
endif()
endif()
set(OpenMP_${LANG}_LIBRARIES "")
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}")
endforeach()
if(NOT TARGET OpenMP::OpenMP_${LANG})
add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED)
endif()
if(OpenMP_${LANG}_FLAGS)
separate_arguments(_OpenMP_${LANG}_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>")
unset(_OpenMP_${LANG}_OPTIONS)
endif()
if(OpenMP_${LANG}_LIBRARIES)
set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}")
endif()
endif()
endif()
endforeach()
unset(_OpenMP_REQ_VARS)
foreach(LANG IN ITEMS C CXX Fortran)
if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
endif()
endforeach()
find_package_handle_standard_args(OpenMP
REQUIRED_VARS ${_OpenMP_REQ_VARS}
VERSION_VAR ${_OpenMP_MIN_VERSION}
HANDLE_COMPONENTS)
set(OPENMP_FOUND ${OpenMP_FOUND})
if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "")
endif()
if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "")
endif()
endif()
if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled")
endif()
unset(OpenMP_C_CXX_TEST_SOURCE)
unset(OpenMP_Fortran_TEST_SOURCE)
unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE)
unset(OpenMP_Fortran_CHECK_VERSION_SOURCE)
unset(OpenMP_Fortran_INCLUDE_LINE)
cmake_policy(POP)

@ -14,7 +14,9 @@
#
# vtkm_rendering Target that contains all the rendering code
#
# vtkm_filter Target that contains all of VTK-m filters
# vtkm_filter Target that contains all of VTK-m pre-built filters
#
# vtkm_source Target that contains all of VTK-m pre-built sources
#
# vtkm::tbb Target that contains tbb related link information
# implicitly linked to by `vtkm_cont` if tbb is enabled

@ -86,7 +86,7 @@ endif()
if(VTKm_ENABLE_OPENMP AND NOT TARGET vtkm::openmp)
cmake_minimum_required(VERSION 3.9...3.15 FATAL_ERROR)
cmake_minimum_required(VERSION 3.12...3.15 FATAL_ERROR)
find_package(OpenMP 4.0 REQUIRED COMPONENTS CXX QUIET)
add_library(vtkm::openmp INTERFACE IMPORTED GLOBAL)

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

@ -22,6 +22,7 @@ include(VTKmWrappers)
# TEST_ARGS <argument_list>
# MPI
# ALL_BACKENDS
# USE_VTKM_JOB_POOL
# <options>
# )
#
@ -46,7 +47,7 @@ function(vtkm_unit_tests)
endif()
set(options)
set(global_options ${options} MPI ALL_BACKENDS)
set(global_options ${options} USE_VTKM_JOB_POOL MPI ALL_BACKENDS)
set(oneValueArgs BACKEND NAME LABEL)
set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
cmake_parse_arguments(VTKm_UT
@ -137,6 +138,11 @@ function(vtkm_unit_tests)
target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
if(VTKm_UT_USE_VTKM_JOB_POOL)
vtkm_setup_job_pool()
set_property(TARGET ${test_prog} PROPERTY JOB_POOL_COMPILE vtkm_pool)
endif()
list(LENGTH per_device_command_line_arguments number_of_devices)
foreach(index RANGE ${number_of_devices})
if(index EQUAL number_of_devices)
@ -145,7 +151,7 @@ function(vtkm_unit_tests)
break()
endif()
if(per_device_command_line_arguments STREQUAL "NONE")
set(device_command_line_argument ${per_device_command_line_arguments})
set(device_command_line_argument)
set(upper_backend ${per_device_suffix})
set(timeout ${per_device_timeout})
set(run_serial ${per_device_serial})

@ -250,7 +250,6 @@ if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
${VTKm_SOURCE_DIR}/CMake/FindTBB.cmake
${VTKm_SOURCE_DIR}/CMake/FindMPI.cmake
${VTKm_SOURCE_DIR}/CMake/FindOpenGL.cmake
${VTKm_SOURCE_DIR}/CMake/FindOpenMP.cmake
DESTINATION ${VTKm_INSTALL_CMAKE_MODULE_DIR}
)

@ -65,8 +65,8 @@ VTK-m Requires:
+ Intel 17.0.4+
+ [CMake](http://www.cmake.org/download/)
+ CMake 3.8+
+ CMake 3.9+ (for OpenMP support)
+ CMake 3.11+ (for Visual Studio generator)
+ CMake 3.12+ (for OpenMP support)
+ CMake 3.13+ (for CUDA support)
Optional dependencies are:

@ -46,8 +46,8 @@
#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/source/Wavelet.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WaveletGenerator.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <cctype> // for std::tolower
@ -142,7 +142,6 @@ using UnstructuredCellList =
using AllCellList = vtkm::ListTagJoin<StructuredCellList, UnstructuredCellList>;
using CoordinateList = vtkm::ListTagBase<vtkm::Vec3f_32, vtkm::Vec3f_64>;
class BenchmarkFilterPolicy : public vtkm::filter::PolicyBase<BenchmarkFilterPolicy>
{
@ -152,8 +151,6 @@ public:
using StructuredCellSetList = StructuredCellList;
using UnstructuredCellSetList = UnstructuredCellList;
using AllCellSetList = AllCellList;
using CoordinateTypeList = CoordinateList;
};
// Class implementing all filter benchmarks:
@ -307,7 +304,7 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet);
(void)result;
return timer.GetElapsedTime();
}
@ -374,7 +371,7 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet);
(void)result;
return timer.GetElapsedTime();
}
@ -400,7 +397,7 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet);
(void)result;
return timer.GetElapsedTime();
}
@ -501,7 +498,7 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet);
(void)result;
return timer.GetElapsedTime();
}
@ -547,7 +544,7 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet);
(void)result;
return timer.GetElapsedTime();
}
@ -649,11 +646,11 @@ class BenchmarkFilters
}
}
template <typename T1, typename T2, typename T3, typename T4>
VTKM_CONT void operator()(const vtkm::cont::CellSetExplicit<T1, T2, T3, T4>& cellSet) const
template <typename T1, typename T2, typename T3>
VTKM_CONT void operator()(const vtkm::cont::CellSetExplicit<T1, T2, T3>& cellSet) const
{
{ // Why does CastAndCall insist on making the cellset const?
using CellSetT = vtkm::cont::CellSetExplicit<T1, T2, T3, T4>;
using CellSetT = vtkm::cont::CellSetExplicit<T1, T2, T3>;
CellSetT& mcellSet = const_cast<CellSetT&>(cellSet);
mcellSet.ResetConnectivity(vtkm::TopologyElementTagPoint{},
vtkm::TopologyElementTagCell{});
@ -954,7 +951,7 @@ void CreateFields(bool needPointScalars, bool needCellScalars, bool needPointVec
vtkm::filter::PointAverage avg;
avg.SetActiveField(CellScalarsName, vtkm::cont::Field::Association::CELL_SET);
avg.SetOutputFieldName("GeneratedPointScalars");
auto outds = avg.Execute(InputDataSet, BenchmarkFilterPolicy());
auto outds = avg.Execute(InputDataSet);
InputDataSet.AddField(
outds.GetField("GeneratedPointScalars", vtkm::cont::Field::Association::POINTS));
PointScalarsName = "GeneratedPointScalars";
@ -977,7 +974,7 @@ void CreateFields(bool needPointScalars, bool needCellScalars, bool needPointVec
vtkm::filter::VectorMagnitude mag;
mag.SetActiveField(PointVectorsName, vtkm::cont::Field::Association::POINTS);
mag.SetOutputFieldName("GeneratedPointScalars");
auto outds = mag.Execute(InputDataSet, BenchmarkFilterPolicy());
auto outds = mag.Execute(InputDataSet);
InputDataSet.AddField(
outds.GetField("GeneratedPointScalars", vtkm::cont::Field::Association::POINTS));
PointScalarsName = "GeneratedPointScalars";
@ -999,7 +996,7 @@ void CreateFields(bool needPointScalars, bool needCellScalars, bool needPointVec
vtkm::filter::CellAverage avg;
avg.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::POINTS);
avg.SetOutputFieldName("GeneratedCellScalars");
auto outds = avg.Execute(InputDataSet, BenchmarkFilterPolicy());
auto outds = avg.Execute(InputDataSet);
InputDataSet.AddField(
outds.GetField("GeneratedCellScalars", vtkm::cont::Field::Association::CELL_SET));
CellScalarsName = "GeneratedCellScalars";
@ -1357,10 +1354,10 @@ int BenchmarkBody(int argc, char** argv, const vtkm::cont::InitializeResult& con
{
std::cout << "Generating " << waveletDim << "x" << waveletDim << "x" << waveletDim
<< " wavelet...\n";
vtkm::worklet::WaveletGenerator gen;
gen.SetExtent({ 0 }, { waveletDim });
vtkm::source::Wavelet source;
source.SetExtent({ 0 }, { waveletDim });
InputDataSet = gen.GenerateDataSet(config.Device);
InputDataSet = source.Execute();
}
if (tetra)

@ -42,7 +42,7 @@ set(benchmarks
)
foreach (benchmark ${benchmarks})
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_filter)
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter)
endforeach ()
if(TARGET vtkm_rendering)

193
docs/ReleaseProcess.md Normal file

@ -0,0 +1,193 @@
Release Process
===============
# High level view
1. Craft Release Branch
- Generate change log
- Commit change log
- Commit update to version.txt
- Merge release branch
2. Tag release
3. Add Gitlab Release Notes
4. Announce
# Craft Release Branch
Construct a git branch named `release_X.Y`
## Generate change log
Construct a `docs/changelog/X.Y/` folder.
Construct a `docs/changelog/X.Y/release-notes.md` file
Use the following template for `release-notes.md`:
```md
VTK-m N Release Notes
=======================
# Table of Contents
1. [Core](#Core)
- Core change 1
2. [ArrayHandle](#ArrayHandle)
3. [Control Environment](#Control-Environment)
4. [Execution Environment](#Execution-Environment)
5. [Worklets and Filters](#Worklets-and-Filters)
6. [Build](#Build)
7. [Other](#Other)
# Core
## Core change 1 ##
changes in core 1
# ArrayHandle
# Control Enviornment
# Execution Environment
# Execution Environment
# Worklets and Filters
# Build
# Other
```
For each individual file in `docs/changelog` move them
to the relevant `release-notes` section.
- Make sure each title and entry in the table of contents use full vtkm names `vtkm::cont::Field` instead of Field
- Make sure each title and entry DOESNT have a peroid at the end
- Make sure any sub-heading as part of the changelog is transformed from `##` to `###`.
- Entries for `Core` are reserved for large changes that significantly improve VTK-m users life, or are
major breaking changes.
## Commit change log
Remove each individual change log file from the git repository
using `git rm docs/changelog/*.md`
Add the changelog to the git history using `git add changelog/X.Y/release-notes.md`
make a commit with the message:
```
Add release notes for vX.Y.Z
```
## Commit update to version.txt
Add a second commit to the `release_X.Y` branch that contains the update
of the `version.txt` file to the correct version. The commit diff should look like:
```
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.4.0
+1.5.0
```
The commit message should read:
```
X.Y.0 is our Nth official release of VTK-m.
The major changes to VTK-m from A.B.C can be found in:
docs/changelog/X.Y/release-notes.md
```
## Merge release branch
At this point you should be ready to merge this branch.
So push to the `release_X.Y` branch to gitlab and open a merge request.
The dashboards should produce a configure warning that the new release git tag
can't be found. This is to be expected.
Before completing the merge it is a good idea to review the rendered markdown of the release notes to ensure that they display properly.
On the merge request page, click on the Changes tab and then for the `release.X.Y` file click the View file button in the upper right.
# Tag Release
Once the merge request is merged we can add the tag.
VTK-m marks the commit that contains the modifications to `version.txt` as the tag location, not the merge commit.
After the merge this would be the second commit shown by git log as shown below:
```
git checkout master
git pull
git log -n2
Merge: d3d3e441 f66d980d
commit f66d980d (HEAD -> release_X.Y.0, gitlab/release_X.Y.0, master)
```
To place the tag at the correct location you will use the following command:
```
git tag -a -f vX.Y.Z SHA1
```
For the above example the `SHA1` would be `f66d980d`
This should prompt you to add a message to the tag. The message should be identical to the one
you used in the commit.
## Push git tags
Now you will need to push the tag back to gitlab so you will need to do the following:
```
git remote add origin_update_tags git@gitlab.kitware.com:vtk/vtk-m.git
git push --tags origin_update_tags
git remote rm origin_update_tags
```
# Add Gitlab Release Notes
Now that the VTK-m release is on gitlab we have to add the associated changelog to the release
entry on gitlab.
Go to `https://gitlab.kitware.com/vtk/vtk-m/-/tags/vX.Y.Z/release/edit` to edit the release page.
Copy the contents of `docs/changelog/X.Y/release-notes.md`
# Email Announcements
Announce the new VTK-m release on the mailing list. You will need to compute
the number of merge requests, changelog entries, and maybe # of authors.
To compute the number of unique committers
```
git log --format="%an" v1.4.0..v1.5.0 | sort -u | wc -l
```
To compute the number of merge requests
```
git log v1.4.0..v1.5.0 | grep 'Merge | wc -l
```
A standard template to use is:
```
Hi All,
VTK-m 1.5.0 is now released, and a special thanks to everyone that has
contributed to VTK-m since our last release. The 1.5.0 release contains
over 100000 merge requests, and 100000 entries to the changelog .
Below are all the entries in the changelog, with more details at (
https://gitlab.kitware.com/vtk/vtk-m/tags/vX.Y.0 ) or in the vtkm
repository at `docs/X.Y/release-notes.md`
1. Core
- Core change 1
2. ArrayHandle
3. Control Environment
4. Execution Environment
5. Worklets and Filters
6. Build
7. Other
```

@ -1,7 +0,0 @@
# 0-sample-topic
This is a sample release note for the change in a topic.
Developers should add similar notes for each topic branch
making a noteworthy change. Each document should be named
and titled to match the topic name to avoid merge conflicts.

File diff suppressed because it is too large Load Diff

@ -1,145 +0,0 @@
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);
}
}
}
}
}
};
```

@ -1,47 +0,0 @@
# Add ability to get an array from a Field for a particular type
Previously, whenever you got an array from a `Field` object from a call to
an `ApplyPolicy`, you would get back a `VariantArrayHandle` that allows you
to cast to multiple types. To use that, you then have to cast it to
multiple different types and multiple different storage.
Often, this is what you want. If you are operating on a field, then you
want to cast to the native type. But there are also cases where you know a
specific type you want. For example, if you are operating on two fields, it
makes sense to find the exact type for the first field and then cast the
second field to that type if necessary rather than pointlessly unroll
templates for the cross of every possible combination. Also, we are not
unrolling for different storage types or attempting to create a virtual
array. Instead, we are using an `ArrayHandleMultiplexer` so that you only
have to compile for this array once.
This is done through a new version of `ApplyPolicy`. This version takes a
type of the array as its first template argument, which must be specified.
This requires having a list of potential storage to try. It will use that
to construct an `ArrayHandleMultiplexer` containing all potential types.
This list of storages comes from the policy. A `StorageList` item was added
to the policy. It is also sometimes necessary for a filter to provide its
own special storage types. Thus, an `AdditionalFieldStorage` type was added
to `Filter` which is set to a `ListTag` of storage types that should be
added to those specified by the policy.
Types are automatically converted. So if you ask for a `vtkm::Float64` and
field contains a `vtkm::Float32`, it will the array wrapped in an
`ArrayHandleCast` to give the expected type.
Here is an example where you are doing an operation on a field and
coordinate system. The superclass finds the correct type of the field. Your
result is just going to follow the type of the field.
``` cpp
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet MyFilter::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<DerivedPolicy> policy)
{
vtkm::cont::CoordinateSystem coords = inDataSet.GetCoordianteSystem();
auto coordsArray = vtkm::filter::ApplyPolicy<T>(coords, policy, *this);
```

@ -1,42 +0,0 @@
# Add ArrayGetValues to retrieve a subset of ArrayHandle values from a device.
An algorithm will often want to pull just a single value (or small subset of
values) back from a device to check the results of a computation. Previously,
there was no easy way to do this, and algorithm developers would often
transfer vast quantities of data back to the host just to check a single value.
The new `vtkm::cont::ArrayGetValue` and `vtkm::cont::ArrayGetValues` functions
simplify this operations and provide a method to just retrieve a portion of an
array.
This utility provides several convenient overloads:
A single id may be passed into ArrayGetValue, or multiple ids may be specified
to ArrayGetValues as an ArrayHandle<vtkm::Id>, a std::vector<vtkm::Id>, a
c-array (pointer and size), or as a brace-enclosed initializer list.
The single result from ArrayGetValue may be returned or written to an output
argument. Multiple results from ArrayGetValues may be returned as an
std::vector<T>, or written to an output argument as an ArrayHandle<T> or a
std::vector<T>.
Examples:
```
vtkm::cont::ArrayHandle<T> data = ...;
// Fetch the first value in an array handle:
T firstVal = vtkm::cont::ArrayGetValue(0, data);
// Fetch the first and third values in an array handle:
std::vector<T> firstAndThird = vtkm::cont::ArrayGetValues({0, 2}, data);
// Fetch the first and last values in an array handle:
std::vector<T> firstAndLast =
vtkm::cont::ArrayGetValues({0, data.GetNumberOfValues() - 1}, data);
// Fetch the first 4 values into an array handle:
const std::vector<vtkm::Id> ids{0, 1, 2, 3};
vtkm::cont::ArrayHandle<T> firstFour;
vtkm::cont::ArrayGetValues(ids, data, firstFour);
```

@ -1,244 +0,0 @@
# Add `ArrayHandleDecorator`.
`ArrayHandleDecorator` is given a `DecoratorImpl` class and a list of one or
more source `ArrayHandle`s. There are no restrictions on the size or type of
the source `ArrayHandle`s.
The decorator implementation class is described below:
```
struct ExampleDecoratorImplementation
{
// Takes one portal for each source array handle (only two shown).
// Returns a functor that defines:
//
// ValueType operator()(vtkm::Id id) const;
//
// which takes an index and returns a value which should be produced by
// the source arrays somehow. This ValueType will be the ValueType of the
// ArrayHandleDecorator.
//
// Both SomeFunctor::operator() and CreateFunctor must be const.
//
template <typename Portal1Type, typename Portal2Type>
SomeFunctor CreateFunctor(Portal1Type portal1, Portal2Type portal2) const;
// Takes one portal for each source array handle (only two shown).
// Returns a functor that defines:
//
// void operator()(vtkm::Id id, ValueType val) const;
//
// which takes an index and a value, which should be used to modify one
// or more of the source arrays.
//
// CreateInverseFunctor is optional; if not provided, the
// ArrayHandleDecorator will be read-only. In addition, if all of the
// source ArrayHandles are read-only, the inverse functor will not be used
// and the ArrayHandleDecorator will be read only.
//
// Both SomeInverseFunctor::operator() and CreateInverseFunctor must be
// const.
//
template <typename Portal1Type, typename Portal2Type>
SomeInverseFunctor CreateInverseFunctor(Portal1Type portal1,
Portal2Type portal2) const;
};
```
Some example implementation classes are provided below:
Reverse a ScanExtended:
```
// Decorator implementation that reverses the ScanExtended operation.
//
// The resulting ArrayHandleDecorator will take an array produced by the
// ScanExtended algorithm and return the original ScanExtended input.
//
// Some interesting things about this:
// - The ArrayHandleDecorator's ValueType will not be the same as the
// ScanPortal's ValueType. The Decorator ValueType is determined by the
// return type of Functor::operator().
// - The ScanPortal has more values than the ArrayHandleDecorator. The
// number of values the ArrayHandleDecorator should hold is set during
// construction and may differ from the arrays it holds.
template <typename ValueType>
struct ScanExtendedToNumIndicesDecorImpl
{
template <typename ScanPortalType>
struct Functor
{
ScanPortalType ScanPortal;
VTKM_EXEC_CONT
ValueType operator()(vtkm::Id idx) const
{
return static_cast<ValueType>(this->ScanPortal.Get(idx + 1) -
this->ScanPortal.Get(idx));
}
};
template <typename ScanPortalType>
Functor<ScanPortalType> CreateFunctor(ScanPortalType portal) const
{
return {portal};
}
};
auto numIndicesOrig = vtkm::cont::make_ArrayHandleCounting(ValueType{0},
ValueType{1},
ARRAY_SIZE);
vtkm::cont::ArrayHandle<vtkm::Id> scan;
vtkm::cont::Algorithm::ScanExtended(
vtkm::cont::make_ArrayHandleCast<vtkm::Id>(numIndicesOrig),
scan);
auto numIndicesDecor = vtkm::cont::make_ArrayHandleDecorator(
ARRAY_SIZE,
ScanExtendedToNumIndicesDecorImpl<ValueType>{},
scan);
```
Combine two other `ArrayHandle`s using an arbitrary binary operation:
```
// Decorator implementation that demonstrates how to create functors that
// hold custom state. Here, the functors have a customizable Operation
// member.
//
// This implementation is used to create a read-only ArrayHandleDecorator
// that combines the values in two other ArrayHandles using an arbitrary
// binary operation (e.g. vtkm::Maximum, vtkm::Add, etc).
template <typename ValueType, typename OperationType>
struct BinaryOperationDecorImpl
{
OperationType Operation;
// The functor use to read values. Note that it holds extra state in
// addition to the portals.
template <typename Portal1Type, typename Portal2Type>
struct Functor
{
Portal1Type Portal1;
Portal2Type Portal2;
OperationType Operation;
VTKM_EXEC_CONT
ValueType operator()(vtkm::Id idx) const
{
return this->Operation(static_cast<ValueType>(this->Portal1.Get(idx)),
static_cast<ValueType>(this->Portal2.Get(idx)));
}
};
// A non-variadic example of a factory function to produce a functor. This
// is where the extra state is passed into the functor.
template <typename P1T, typename P2T>
Functor<P1T, P2T> CreateFunctor(P1T p1, P2T p2) const
{
return {p1, p2, this->Operation};
}
};
BinaryOperationDecorImpl<ValueType, vtkm::Maximum> factory{vtkm::Maximum{}};
auto decorArray = vtkm::cont::make_ArrayHandleDecorator(ARRAY_SIZE,
factory,
array1,
array2);
```
A factory that does a complex and invertible operation on three portals:
```
// Decorator implemenation that demonstrates how to write invertible functors
// that combine three array handles with complex access logic. The resulting
// ArrayHandleDecorator can be both read from and written to.
//
// Constructs functors that take three portals.
//
// The first portal's values are accessed in reverse order.
// The second portal's values are accessed in normal order.
// The third portal's values are accessed via ((idx + 3) % size).
//
// Functor will return the max of the first two added to the third.
//
// InverseFunctor will update the third portal such that the Functor would
// return the indicated value.
struct InvertibleDecorImpl
{
// The functor used for reading data from the three portals.
template <typename Portal1Type, typename Portal2Type, typename Portal3Type>
struct Functor
{
using ValueType = typename Portal1Type::ValueType;
Portal1Type Portal1;
Portal2Type Portal2;
Portal3Type Portal3;
VTKM_EXEC_CONT ValueType operator()(vtkm::Id idx) const
{
const auto idx1 = this->Portal1.GetNumberOfValues() - idx - 1;
const auto idx2 = idx;
const auto idx3 = (idx + 3) % this->Portal3.GetNumberOfValues();
const auto v1 = this->Portal1.Get(idx1);
const auto v2 = this->Portal2.Get(idx2);
const auto v3 = this->Portal3.Get(idx3);
return vtkm::Max(v1, v2) + v3;
}
};
// The functor used for writing. Only Portal3 is written to, the other
// portals may be read-only.
template <typename Portal1Type, typename Portal2Type, typename Portal3Type>
struct InverseFunctor
{
using ValueType = typename Portal1Type::ValueType;
Portal1Type Portal1;
Portal2Type Portal2;
Portal3Type Portal3;
VTKM_EXEC_CONT void operator()(vtkm::Id idx, const ValueType &vIn) const
{
const auto v1 = this->Portal1.Get(this->Portal1.GetNumberOfValues() - idx - 1);
const auto v2 = this->Portal2.Get(idx);
const auto vNew = static_cast<ValueType>(vIn - vtkm::Max(v1, v2));
this->Portal3.Set((idx + 3) % this->Portal3.GetNumberOfValues(), vNew);
}
};
// Factory function that takes 3 portals as input and creates an instance
// of Functor with them. Variadic template parameters are used here, but are
// not necessary.
template <typename... PortalTs>
Functor<typename std::decay<PortalTs>::type...>
CreateFunctor(PortalTs&&... portals) const
{
VTKM_STATIC_ASSERT(sizeof...(PortalTs) == 3);
return {std::forward<PortalTs>(portals)...};
}
// Factory function that takes 3 portals as input and creates an instance
// of InverseFunctor with them. Variadic template parameters are used here,
// but are not necessary.
template <typename... PortalTs>
InverseFunctor<typename std::decay<PortalTs>::type...>
CreateInverseFunctor(PortalTs&&... portals) const
{
VTKM_STATIC_ASSERT(sizeof...(PortalTs) == 3);
return {std::forward<PortalTs>(portals)...};
}
};
// Note that only ah3 must be writable for ahInv to be writable. ah1 and ah2
// may be read-only arrays.
auto ahInv = vtkm::cont::make_ArrayHandleDecorator(ARRAY_SIZE,
InvertibleDecorImpl{},
ah1,
ah2,
ah3);
```

@ -1,183 +0,0 @@
# 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.
## 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);
}
```

@ -1,61 +0,0 @@
# Added ArrayHandleSOA
`ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic
storage) except that if you specify a `ValueType` of a `Vec` or a
`Vec`-like, it will actually store each component in a separate physical
array. When data are retrieved from the array, they are reconstructed into
`Vec` objects as expected.
The intention of this array type is to help cover the most common ways data
is lain out in memory. Typically, arrays of data are either an "array of
structures" like the basic storage where you have a single array of
structures (like `Vec`) or a "structure of arrays" where you have an array
of a basic type (like `float`) for each component of the data being
represented. The `ArrayHandleSOA` makes it easy to cover this second case
without creating special types.
`ArrayHandleSOA` can be constructed from a collection of `ArrayHandle` with
basic storage. This allows you to construct `Vec` arrays from components
without deep copies.
``` cpp
std::vector<vtkm::Float32> accel0;
std::vector<vtkm::Float32> accel1;
std::vector<vtkm::Float32> accel2;
// Let's say accel arrays are set to some field of acceleration vectors by
// some other software.
vtkm::cont::ArrayHandle<vtkm::Float32> accelHandle0 = vtkm::cont::make_ArrayHandle(accel0);
vtkm::cont::ArrayHandle<vtkm::Float32> accelHandle1 = vtkm::cont::make_ArrayHandle(accel1);
vtkm::cont::ArrayHandle<vtkm::Float32> accelHandle2 = vtkm::cont::make_ArrayHandle(accel2);
vtkm::cont::ArrayHandleSOA<vtkm::Vec3f_32> accel = { accelHandle0, accelHandle1, accelHandle2 };
```
Also provided are constructors and versions of `make_ArrayHandleSOA` that
take `std::vector` or C arrays as either initializer lists or variable
arguments.
``` cpp
std::vector<vtkm::Float32> accel0;
std::vector<vtkm::Float32> accel1;
std::vector<vtkm::Float32> accel2;
// Let's say accel arrays are set to some field of acceleration vectors by
// some other software.
vtkm::cont::ArrayHandleSOA<vtkm::Vec3f_32> accel = { accel0, accel1, accel2 };
```
However, setting arrays is a little awkward because you also have to
specify the length. This is done either outside the initializer list or as
the first argument.
``` cpp
vtkm::cont::make_ArrayHandleSOA({ array0, array1, array2 }, ARRAY_SIZE);
```
``` cpp
vtkm::cont::make_ArrayHandleSOA(ARRAY_SIZE, array0, array1, array2);
```

@ -1,15 +0,0 @@
# Updating structured cell locators
VTK-m will mow allow locating containing cells for a point using `CellLocatorUniformGrid`
and `CellLocatorRectilinearGrid` for 2D grids.
Users are required to create the locator objects as they normally would.
However, the `FindCell` method in `vtkm::exec::CellLocator` still requires users
to pass a 3D point as an input.
Further, the structured grid locators no longer use the `vtkm::exec::WorldToParametricCoordinates`
method to return parametric coordinates, instead they use fast paths for locating
points in a cell of an axis-aligned grid.
Another change for the `CellLocatorRectilinearGrid` is that now it uses binary search
on individual component arrays to search for a point.

@ -1,8 +0,0 @@
# CellSets now don't have a name
The requirement that `vtkm::cont::CellSets` have a name was so
cell based `vtkm::cont::Field`'s could be associated with the
correct CellSet in a `vtkm::cont::DataSet`.
Now that `DataSet`'s don't support multiple CellSets, we can remove
the `CellSet` name member variable.

@ -1,11 +0,0 @@
# DataSet queries for CoordinateSystem Indices don't throw
Asking for the index of a `vtkm::cont::CoordinateSystem` by
name now returns a `-1` when no matching item has been found instead of throwing
an exception.
This was done to make the interface of `vtkm::cont::DataSet` to follow the guideline
"Only unrepresentable things should raise exceptions". The index of a non-existent item
is representable by `-1` and therefore we shouldn't throw, like wise the methods that return
references can still throw exceptions as you can't have a reference to an non-existent item.

@ -1,29 +0,0 @@
# DataSet only has a single vtkm::cont::CellSet
Multiple `vtkm::cont::CellSets` on a datasets increased the
complexity of using VTK-m correctly without any significant
benefits.
It had the effect that `vtkm::cont::Fields` that representing
cell fields needed to be associated with a given cellset. This
has to be a loose coupling to allow for filters to generate
new output cellsets. At the same time it introduced errors when
that output had a different name.
It raised questions about how should filters propagate cell fields.
Should a filter drop all cell fields not associated with the active
CellSet, or is that too aggressive given the fact that maybe the
algorithm just mistakenly named the field, or the IO routine added
a field with the wrong cellset name.
It increased the complexity of filters, as the developer needed to
determine if the algorithm should support execution on a single `CellSet` or
execution over all `CellSets`.
Given these issues it was deemed that removing multiple `CellSets` was
the correct way forward. People using multiple `CellSets` will need to
move over to `vtkm::cont::MultiBlock` which supports shared points and
fields between multiple blocks.

@ -1,16 +0,0 @@
# Added Source class hierarchy
A new class hierarchy for dataset source was added. The intention is to
consolidate and refactor various (procedural) dataset generators for unit
tests, especially the multiple copy&past-ed implementations of the Tangle
field. As they are compiled into a library rather than as header files,
we also expect the overall compile time to decrease.
The public interface of dataset source is modeled after Filter. A new DataSet
is returned by calling the Execute() method of the dataset source, for example:
```cpp
vtkm::Id3 dims(4, 4, 4);
vtkm::source::Tangle tangle(dims);
vtkm::cont::DataSet dataSet = tangle.Execute();
```

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

@ -1,5 +0,0 @@
# Fields now don't require the associated CellSet name
Now that `vtkm::cont::DataSet` can only have a single `vtkm::cont::CellSet`
the requirement that cell based `vtkm::cont::Field`s need a CellSet name
has been lifted.

@ -1,4 +0,0 @@
# vtkm::cont::Filter now don't have an active cell set
`vtkm::filter::FilterField` has removed the concept of `ActiveCellSetIndex`. This
has been done as `vtkm::cont::DataSet` now only contains a single `vtkm::cont::CellSet`.

@ -1,9 +0,0 @@
# FilterField now provides all functionality of FilterCell
The FilterCell was a subclass of `vtkm::filter::FilterField` and behaves essentially the same
but provided the pair of methods `SetActiveCellSetIndex` and `GetActiveCellSetIndex`.
It was a common misconception that `FilterCell` was meant for Cell based algorithms, instead of
algorithms that required access to the active `vtkm::cont::CellSet`.
By moving `SetActiveCellSetIndex` and `GetActiveCellSetIndex` to FilterField, we remove this confusion.

@ -1,19 +0,0 @@
# Fix cell derivatives for polygon cell shape
For polygon cell shapes (that are not triangles or quadrilaterals),
interpolations are done by finding the center point and creating a triangle
fan around that point. Previously, the gradient was computed in the same
way as interpolation: identifying the correct triangle and computing the
gradient for that triangle.
The problem with that approach is that makes the gradient discontinuous at
the boundaries of this implicit triangle fan. To make things worse, this
discontinuity happens right at each vertex where gradient calculations
happen frequently. This means that when you ask for the gradient at the
vertex, you might get wildly different answers based on floating point
imprecision.
Get around this problem by creating a small triangle around the point in
question, interpolating values to that triangle, and use that for the
gradient. This makes for a smoother gradient transition around these
internal boundaries.

@ -1,43 +0,0 @@
# Invoker now a member of all vtkm::filters
To simplify how vtkm filters are written we have made each vtkm::filter
have a `vtkm::cont::Invoker` as member variable. The goal with this change
is provide an uniform API for launching all worklets from within a filter.
Lets consider the PointElevation filter. Previous to these changes the
`DoExecute` would need to construct the correct dispatcher with the
correct parameters as seen below:
```cpp
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet PointElevation::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<DerivedPolicy>)
{
vtkm::cont::ArrayHandle<vtkm::Float64> outArray;
vtkm::worklet::DispatcherMapField<vtkm::worklet::PointElevation> dispatcher(this->Worklet);
dispatcher.Invoke(field, outArray);
...
}
```
With these changes the filter can instead use `this->Invoke` and have
the correct dispatcher executed. This makes it easier to teach and
learn how to write new filters.
```cpp
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet PointElevation::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<DerivedPolicy>)
{
vtkm::cont::ArrayHandle<vtkm::Float64> outArray;
this->Invoke(this->Worklet, field, outArray);
...
}
```

@ -1,6 +0,0 @@
# Invoker moved to vtkm::cont
Previously, `Invoker` was located in the `vtkm::worklet` namespace to convey
it was a replacement for using `vtkm::worklet::Dispatcher*`. In actuality
it should be in `vtkm::cont` as it is the proper way to launch worklets
for execution, and that shouldn't exist inside the `worklet` namespace.

@ -1,13 +0,0 @@
# Lagrangian Coherent Strucutres (LCS) Filter for VTK-m
The new filter `vtkm::filter::LagrangianStructures` is meant for Finite Time
Lyapunov Exponent (FTLE) calculation using VTK-m.
The filter allows users to calculate FTLE in two ways
1. Provide a dataset with a vector field, which will be used to generate a flow
map.
2. Provide a dataset containing a flow map, which can be readily used for the
FTLE field calculation.
The filter returns a dataset with a point field named FTLE.
Is the input is strucutred and an auxiliary grid was not used, the filter will
add the field to the original dataset set, else a new structured dataset is returned.

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

@ -1,16 +0,0 @@
# `MultiBlock` renamed to `PartitionedDataSet`
The `MultiBlock` class has been renamed to `PartitionedDataSet`, and its API
has been refactored to refer to "partitions", rather than "blocks".
Additionally, the `AddBlocks` method has been changed to `AppendPartitions` to
more accurately reflect the operation performed. The associated
`AssignerMultiBlock` class has also been renamed to
`AssignerPartitionedDataSet`.
This change is motivated towards unifying VTK-m's data model with VTK. VTK has
started to move away from `vtkMultiBlockDataSet`, which is a hierarchical tree
of nested datasets, to `vtkPartitionedDataSet`, which is always a flat vector
of datasets used to assist geometry distribution in multi-process environments.
This simplifies traversal during processing and clarifies the intent of the
container: The component datasets are partitions for distribution, not
organizational groupings (e.g. materials).

@ -1,18 +0,0 @@
# `SurfaceNormals` filter can now orient normals.
The `OrientNormals` worklet has been added to the `SurfaceNormals` filter, and
is enabled by turning on the `AutoOrientNormals` option. This feature ensures
that all normals generated by the filter will point out of the dataset (or
inward if the `FlipNormals` option is true). In addition,
`SurfaceNormals` now has a `Consistency` option that forces all triangle
windings to be consistent with the cell normal direction (the cell points are
specified in counter-clockwise order around the normal).
This functionality is provided by the following new worklets:
* OrientNormals
* RunOrientCellNormals
* RunOrientPointNormals
* RunOrientPointAndCellNormals
* RunFlipNormals
* TriangleWinding

@ -1,20 +0,0 @@
# Updating particle status for advection
There are now special statuses for Particle, Integrator, and Evaluator.
The particle advection modules only supported statuses for particles and made it
difficult to handle advanced integtator statuses.
Now each of the three important modules return their own statuses
Particles have `vtkm::worklet::particleadvection::ParticleStatus`,
Integrators have `vtkm::worklet::particleadvection::IntegratorStatus`, and
Evaluators have `vtkm::worklet::particleadvection::EvaluatorStatus`.
Further, names of the statuses in `vtkm::worklet::particleadvection::ParticleStatus`
have changed
`ParticleStatus::STATUS_OK` is now `ParticleStatus::SUCCESS`, and there is another
status `ParticleStatus::TOOK_ANY_STEPS` which is active if the particle has taken
at least one step with the current data.
There are few more changes that allow particle advection in 2D structured grids.

@ -1,80 +0,0 @@
# CMake vtkm_add_target_information() makes using vtk-m easier
This higher order function allow build-systems that use VTK-m
to use `add_library` or `add_executable` calls but still have an
easy to way to get the required information to have VTK-m using
compilation units compile correctly.
```cmake
vtkm_add_target_information(
target[s]
[ DROP_UNUSED_SYMBOLS ]
[ MODIFY_CUDA_FLAGS ]
[ EXTENDS_VTKM ]
[ DEVICE_SOURCES <source_list> ]
)
```
Usage:
```cmake
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)
```
## Options to vtkm_add_target_information
- DROP_UNUSED_SYMBOLS: If enabled will apply the appropiate link
flags to drop unused VTK-m symbols. This works as VTK-m is compiled with
-ffunction-sections which allows for the linker to remove unused functions.
If you are building a program that loads runtime plugins that can call
VTK-m this most likely shouldn't be used as symbols the plugin expects
to exist will be removed.
Enabling this will help keep library sizes down when using static builds
of VTK-m as only the functions you call will be kept. This can have a
dramatic impact on the size of the resulting executable / shared library.
- MODIFY_CUDA_FLAGS: If enabled will add the required -arch=<ver> flags
that VTK-m was compiled with. If you have multiple libraries that use
VTK-m calling `vtkm_add_target_information` multiple times with
`MODIFY_CUDA_FLAGS` will cause duplicate compiler flags. To resolve this issue
you can; pass all targets and sources to a single `vtkm_add_target_information`
call, have the first one use `MODIFY_CUDA_FLAGS`, or use the provided
standalone `vtkm_get_cuda_flags` function.
- DEVICE_SOURCES: The collection of source files that are used by `target(s)` 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 used,
passed across library boundaries, and derived from.
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 use VTK-m as implementation detail, doesn't expose VTK-m
types to consumers. This is supported no matter if CUDA is enabled.
- Wanting to extend VTK-m and provide these types to consumers.
This is only supported when CUDA isn't enabled. Otherwise we need to ERROR!
- Wanting to pass known VTK-m types across library boundaries for others
to use in filters/worklets. This is only supported when CUDA isn't enabled. Otherwise we need to ERROR!
For most consumers they can ignore the `EXTENDS_VTKM` property as the default will be correct.
The `vtkm_add_target_information` higher order function leverages the `vtkm_add_drop_unused_function_flags` and
`vtkm_get_cuda_flags` functions which can be used by VTK-m consuming applications.
The `vtkm_add_drop_unused_function_flags` function implements all the behavior of `DROP_UNUSED_SYMBOLS` for a single
target.
The `vtkm_get_cuda_flags` function implements a general form of `MODIFY_CUDA_FLAGS` but instead of modiyfing
the `CMAKE_CUDA_FLAGS` it will add the flags to any variable passed to it.

@ -1,35 +0,0 @@
# Refactor topology mappings to clarify meaning.
The `From` and `To` nomenclature for topology mapping has been confusing for
both users and developers, especially at lower levels where the intention of
mapping attributes from one element to another is easily conflated with the
concept of mapping indices (which maps in the exact opposite direction).
These identifiers have been renamed to `VisitTopology` and `IncidentTopology`
to clarify the direction of the mapping. The order in which these template
parameters are specified for `WorkletMapTopology` have also been reversed,
since eventually there may be more than one `IncidentTopology`, and having
`IncidentTopology` at the end will allow us to replace it with a variadic
template parameter pack in the future.
Other implementation details supporting these worklets, include `Fetch` tags,
`Connectivity` classes, and methods on the various `CellSet` classes (such as
`PrepareForInput` have also reversed their template arguments. These will need
to be cautiously updated.
The convenience implementations of `WorkletMapTopology` have been renamed for
clarity as follows:
```
WorkletMapPointToCell --> WorkletVisitCellsWithPoints
WorkletMapCellToPoint --> WorkletVisitPointsWithCells
```
The `ControlSignature` tags have been renamed as follows:
```
FieldInTo --> FieldInVisit
FieldInFrom --> FieldInMap
FromCount --> IncidentElementCount
FromIndices --> IncidentElementIndices
```

@ -1,10 +0,0 @@
# Remove ArrayPortalShrink, behavior subsumed by ArrayHandleView
ArrayPortalShrink originaly allowed a user to pass in a delegate array portal
and then shrink the reported array size without actually modifying the
underlying allocation. An iterator was also provided that would
correctly iterate over the shrunken size of the stored array.
Instead of directly shrinking the original array, it is prefered
to create an ArrayHandleView from an ArrayHandle and then specify the
number of values to use in the ArrayHandleView constructor.

@ -1,29 +0,0 @@
# A `ScanExtended` device algorithm has been added.
This new scan algorithm produces an array that contains both an inclusive scan
and an exclusive scan in the same array:
```
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayGetValue.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleView.h>
vtkm::cont::ArrayHandle<T> inputData = ...;
const vtkm::Id size = inputData.GetNumberOfValues();
vtkm::cont::ArrayHandle<T> extendedScan;
vtkm::cont::Algorithm::ScanExtended(inputData, extendedScan);
// The exclusive scan is the first `inputSize` values starting at index 0:
auto exclusiveScan = vtkm::cont::make_ArrayHandleView(extendedScan, 0, size);
// The inclusive scan is the first `inputSize` values starting at index 1:
auto inclusiveScan = vtkm::cont::make_ArrayHandleView(extendedScan, 1, size);
// The total sum of the input data is the last value in the extended scan.
const T totalSum = vtkm::cont::ArrayGetValue(size, extendedScan);
```
This can also be thought of as an exclusive scan that appends the total sum,
rather than returning it.

@ -1,21 +0,0 @@
# Simplify creating Fields from ArrayHandles
VTK-m now offers `make_FieldPoint` and `make_FieldCell` functions
that reduce the complexity of construction `vtkm::cont::Fields`
from `vtkm::cont::ArrayHandles`.
Previously to construct a point and cell fields you would do:
```cpp
vtkm::cont::ArrayHandle<int> pointHandle;
vtkm::cont::ArrayHandle<int> cellHandle;
vtkm::cont::Field pointField("p", vtkm::cont::Field::Association::POINTS, pointHandle);
vtkm::cont::Field cellField("c", vtkm::cont::Field::Association::CELL_SET, "cells", cellHandle);
```
Now with the new `make_` functions you can do:
```cpp
vtkm::cont::ArrayHandle<int> pointHandle;
vtkm::cont::ArrayHandle<int> cellHandle;
auto pointField = vtkm::cont::make_FieldPoint("p", pointHandle);
auto cellField = vtkm::cont::make_FieldCell("c", "cells", cellHandle);
```

@ -1,27 +0,0 @@
# Simplify creating results for Filters
As part of the process of making VTK-m filters easier to write for newcomers
whe have a couple of changes to make constructing the output `vtkm::cont::DataSet`
easier.
First we have moved the `CreateResult` functions out of the internals namespace
and directly into `vtkm::filter`. This makes it clearer to developers that this
was the 'proper' way to construct the output DataSet.
Second we have streamlined the collection of `vtkm::filter::CreateResult` methods to
require the user to provide less information and provide clearer names explaing what
they do.
To construct output identical to the input but with a new field you now just pass
the `vtkm::filter::FieldMetadata` as a paramter instead of explictly stating
the field association, and the possible cell set name:
```cpp
return CreateResult(input, newField, name, fieldMetadata);
```
To construct output identical to the input but with a cell field added you
can now pass the `vtkm::cont::CellSet` as a paramter instead of explictly stating
the field association, and the cell set name:
```cpp
return CreateResultFieldCell(input, newCellField, name, cellset);
```

@ -1,7 +0,0 @@
# Simplify examples
Lots of the examples were out of date or way too verbose. The examples have
been simplified and brought up to modern VTK-m conventions.
We have also added a "hello worklet" example to be a minimal example of
creating a working algorithm (wrapped in a filter) in VTK-m (and used).

@ -1,31 +0,0 @@
# Provide a simplified way to state allowed value types for VTK-m filters
Previously VTK-m filters used a specialization of `vtkm::filter::FilterTraits<>` to control
the acceptable input value types. For example if the `WarpVector` filter want to only allow
`vtkm::Vec3f_32` and `vtkm::Vec3f_64` it would use:
```cpp
namespace vtkm { namespace filter {
template <>
class FilterTraits<WarpVector>
{
public:
// WarpVector can only applies to Float and Double Vec3 arrays
using InputFieldTypeList = vtkm::TypeListTagFieldVec3;
};
}}
```
This increase the complexity of writing filters. To make this easier VTK-m now looks for
a `SupportedTypes` define on the filter when a `vtkm::filter::FilterTraits` specialization
doesn't exist. This allows filters to succinctly specify supported types, such as seen below
for the `WarpVector` filter.
```cpp
class WarpVector : public vtkm::filter::FilterField<WarpVector>
{
public:
using SupportedTypes = vtkm::TypeListTagFieldVec3;
...
};
```

@ -1,21 +0,0 @@
# Copy Threshold output to a CellSetExplicit
Perhaps a better title for this change would be "Make the Threshold filter
not totally useless."
A long standing issue with the Threshold filter is that its output CellSet
was stored in a CellSetPermutation. This made Threshold hyper- efficient
because it required hardly any data movement to implement. However, the
problem was that any other unit that had to use the CellSet failed. To have
VTK-m handle that output correctly in other filters and writers, they all
would have to check for the existance of CellSetPermutation. And
CellSetPermutation is templated on the CellSet type it is permuting, so all
units would have to compile special cases for all these combinations. This
is not likely to be feasible in any static solution.
The simple solution, implemented here, is to deep copy the cells to a
CellSetExplicit, which is a known type that is already used everywhere in
VTK-m. The solution is a bit disappointing since it requires more memory
and time to build. But it is on par with solutions in other libraries (like
VTK). And it really does not matter how efficient the old solution was if
it was useless.

@ -1,39 +0,0 @@
# Recursive base component queries to VecTraits
This change adds a recursive `BaseComponentType` to `VecTraits` that
recursively finds the base (non-`Vec`) type of a `Vec`. This is useful when
dealing with potentially nested `Vec`s (e.g. `Vec<Vec<T, M>, N>`) and you
want to know the precision of the math being defined.
``` cpp
using NestedVec = vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 8>;
// ComponentType becomes vtkm::Vec<vtkm::Float32, 3>
using ComponentType = typename vtkm::VecTraits<NestedVec>::ComponentType;
// BaseComponentType becomes vtkm::Float32
using BaseComponentType = typename vtkm::VecTraits<NestedVec>::BaseComponentType;
```
Also added the ability to `VecTraits` to change the component type of a
vector. The template `RepalceComponentType` resolves to a `Vec` of the same
type with the component replaced with a new type. The template
`ReplaceBaseComponentType` traverses down a nested type and replaces the
base type.
``` cpp
using NestedVec = vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 8>;
// NewVec1 becomes vtkm::Vec<vtkm::Float64, 8>
using NewVec1 =
typename vtkm::VecTraits<NestedVec>::template ReplaceComponentType<vtkm::Float64>;
// NewVec2 becomes vtkm::Vec<vtkm::Vec<vtkm::Float64, 3>, 8>
using NewVec1 =
typename vtkm::VecTraits<NestedVec>::template ReplaceBaseComponentType<vtkm::Float64>;
```
This functionality replaces the functionality in `vtkm::BaseComponent`. Unfortunately,
`vtkm::BaseComponent` did not have the ability to replace the base component and
there was no straightforward way to implement that outside of `VecTraits`.

@ -1,22 +0,0 @@
# Add aliases for common Vec types
Specifying `Vec` types can be verbose. For example, to simply express a
vector in 3-space, you would need a declaration like this:
``` cpp
vtkm::Vec<vtkm::FloatDefault, 3>
```
This is very verbose and frankly confusing to users. To make things easier,
we have introduced several aliases for common `Vec` types. For example, the
above type can now be referenced simply with `vtkm::Vec3f`, which is a
3-vec of floating point values of the default width. If you want to specify
the width, then you can use either `vtkm::Vec3f_32` or `vtkm::Vec3f_64`.
There are likewise types introduced for integers and unsigned integers
(e.g. `vtkm::Vec3i` and `vtkm::Vec3ui`). You can specify the width of these
all the way down to 8 bit (e.g. `vtkm::Vec3ui_8`, `vtkm::Vec3ui_16`,
`vtkm::Vec3ui_32`, and `vtkm::Vec3ui_64`).
For completeness, `vtkm::Id4` was added as well as `vtkm::IdComponent2`,
`vtkm::IdComponent3`, and `vtkm::IdComponent4`.

@ -1,11 +0,0 @@
# vtkm::Vec const& operator[] is now `constexpr`
This was done to allow for developers to write normal operations on vtkm::Vec but have
the resolved at compile time, allowing for both readible code and no runtime cost.
Now you can do things such as:
```cxx
constexpr vtkm::Id2 dims(16,16);
constexpr vtkm::Float64 dx = vtkm::Float64(4.0 * vtkm::Pi()) / vtkm::Float64(dims[0] - 1);
```

@ -1,12 +0,0 @@
# 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`.

@ -139,14 +139,11 @@ public:
std::string getOption(const std::string& option) const
{
std::size_t index = static_cast<std::size_t>(this->findOption(option));
if (index >= 0)
std::string val = this->mCLOptions[index];
auto valPos = val.find("=");
if (valPos)
{
std::string val = this->mCLOptions[index];
auto valPos = val.find("=");
if (valPos)
{
return val.substr(valPos + 1);
}
return val.substr(valPos + 1);
}
return std::string("");
}

@ -15,7 +15,7 @@ find_package(VTKm REQUIRED QUIET)
if(TARGET vtkm_rendering)
add_executable(Demo Demo.cxx)
target_link_libraries(Demo PRIVATE vtkm_rendering)
target_link_libraries(Demo PRIVATE vtkm_filter vtkm_rendering)
vtkm_add_target_information(Demo
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Demo.cxx)

@ -29,7 +29,6 @@ namespace worklet
struct HelloWorklet : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn inVector, FieldOut outMagnitude);
using ExecutionSignature = void(_1, _2);
VTKM_EXEC void operator()(const vtkm::Vec3f& inVector, vtkm::FloatDefault& outMagnitude) const
{

@ -199,8 +199,9 @@ inline vtkm::cont::DataSet Make3DExplicitDataSet()
return dataSet;
}
template <typename T>
int TestMetrics(const char* outFileName, vtkm::cont::DataSet data, T filter)
int TestMetrics(const char* outFileName,
vtkm::cont::DataSet data,
vtkm::filter::MeshQuality& filter)
{
vtkm::cont::DataSet outputData;
try
@ -255,22 +256,10 @@ int main(int argc, char* argv[])
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)
};
// A cell metric is now computed for every shape type that exists in the
// input dataset.
vtkm::filter::CellMetric shapeMetric = vtkm::filter::CellMetric::VOLUME;
vtkm::filter::MeshQuality filter(shapeMetrics);
try
{
input = reader.ReadDataSet(); //FIELD not supported errors here, but doesnt affect data
@ -281,6 +270,8 @@ int main(int argc, char* argv[])
std::cerr << "Error occured while reading input. Exiting" << std::endl;
return 1;
}
vtkm::filter::MeshQuality filter(shapeMetric);
TestMetrics(outFileName, input, filter);
return 0;
}

@ -14,7 +14,7 @@ project(Oscillator CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Oscillator Oscillator.cxx)
target_link_libraries(Oscillator PRIVATE vtkm_filter)
target_link_libraries(Oscillator PRIVATE vtkm_source)
vtkm_add_target_information(Oscillator
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Oscillator.cxx)

@ -22,7 +22,7 @@
#include <vtkm/cont/TryExecute.h>
#include <vtkm/filter/OscillatorSource.h>
#include <vtkm/source/Oscillator.h>
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h> /* unlink */
@ -58,7 +58,7 @@ static inline std::string& trim(std::string& s)
// ----------------------------------------------------------------------------
void read_oscillators(std::string filePath, vtkm::filter::OscillatorSource& filter)
void read_oscillators(std::string filePath, vtkm::source::Oscillator& source)
{
std::ifstream in(filePath);
if (!in)
@ -87,15 +87,15 @@ void read_oscillators(std::string filePath, vtkm::filter::OscillatorSource& filt
if (stype == "damped")
{
filter.AddDamped(x, y, z, r, omega0, zeta);
source.AddDamped(x, y, z, r, omega0, zeta);
}
else if (stype == "decaying")
{
filter.AddDecaying(x, y, z, r, omega0, zeta);
source.AddDecaying(x, y, z, r, omega0, zeta);
}
else if (stype == "periodic")
{
filter.AddPeriodic(x, y, z, r, omega0, zeta);
source.AddPeriodic(x, y, z, r, omega0, zeta);
}
}
}
@ -303,22 +303,19 @@ int main(int argc, char** argv)
std::cout << " - end: " << endTime << std::endl;
std::cout << "=======================================\n" << std::endl;
vtkm::cont::DataSetBuilderUniform builder;
vtkm::cont::DataSet dataset = builder.Create(vtkm::Id3(sizeX, sizeY, sizeZ));
vtkm::filter::OscillatorSource filter;
read_oscillators(oscillatorConfigFile, filter);
vtkm::source::Oscillator source(vtkm::Id3{ sizeX, sizeY, sizeZ });
read_oscillators(oscillatorConfigFile, source);
std::cout << "=========== start computation ============" << std::endl;
int count = 0;
while (currentTime < endTime)
{
filter.SetTime(currentTime);
vtkm::cont::DataSet rdata = filter.Execute(dataset);
source.SetTime(currentTime);
vtkm::cont::DataSet rdata = source.Execute();
if (generateOutput)
{
vtkm::cont::ArrayHandle<vtkm::Float64> tmp;
rdata.GetField("oscillation", vtkm::cont::Field::Association::POINTS).GetData().CopyTo(tmp);
rdata.GetField("scalars", vtkm::cont::Field::Association::POINTS).GetData().CopyTo(tmp);
double* values = tmp.GetStorage().GetArray();
writeData(outputDirectory, count++, sizeX, sizeY, sizeZ, values);
}

@ -1 +1 @@
1.4.0
1.5.0

@ -25,6 +25,7 @@ set(headers
CellClassification.h
CellShape.h
CellTraits.h
Deprecated.h
Flags.h
Geometry.h
Hash.h
@ -77,6 +78,8 @@ if(VTKm_ENABLE_LOGGING)
endif()
add_subdirectory(thirdparty/optionparser)
add_subdirectory(thirdparty/taotuple)
add_subdirectory(thirdparty/lcl)
add_subdirectory(testing)
add_subdirectory(internal)

@ -13,6 +13,17 @@
#include <vtkm/StaticAssert.h>
#include <vtkm/Types.h>
#include <lcl/Polygon.h>
#include <lcl/Shapes.h>
// Vtk-c does not have tags for Empty and PolyLine. Define dummy tags here to
// avoid compilation errors. These tags are not used anywhere.
namespace lcl
{
struct Empty;
struct PolyLine;
}
namespace vtkm
{
@ -22,21 +33,21 @@ namespace vtkm
enum CellShapeIdEnum
{
// Linear cells
CELL_SHAPE_EMPTY = 0,
CELL_SHAPE_VERTEX = 1,
CELL_SHAPE_EMPTY = lcl::ShapeId::EMPTY,
CELL_SHAPE_VERTEX = lcl::ShapeId::VERTEX,
//CELL_SHAPE_POLY_VERTEX = 2,
CELL_SHAPE_LINE = 3,
CELL_SHAPE_LINE = lcl::ShapeId::LINE,
CELL_SHAPE_POLY_LINE = 4,
CELL_SHAPE_TRIANGLE = 5,
CELL_SHAPE_TRIANGLE = lcl::ShapeId::TRIANGLE,
//CELL_SHAPE_TRIANGLE_STRIP = 6,
CELL_SHAPE_POLYGON = 7,
CELL_SHAPE_POLYGON = lcl::ShapeId::POLYGON,
//CELL_SHAPE_PIXEL = 8,
CELL_SHAPE_QUAD = 9,
CELL_SHAPE_TETRA = 10,
CELL_SHAPE_QUAD = lcl::ShapeId::QUAD,
CELL_SHAPE_TETRA = lcl::ShapeId::TETRA,
//CELL_SHAPE_VOXEL = 11,
CELL_SHAPE_HEXAHEDRON = 12,
CELL_SHAPE_WEDGE = 13,
CELL_SHAPE_PYRAMID = 14,
CELL_SHAPE_HEXAHEDRON = lcl::ShapeId::HEXAHEDRON,
CELL_SHAPE_WEDGE = lcl::ShapeId::WEDGE,
CELL_SHAPE_PYRAMID = lcl::ShapeId::PYRAMID,
NUMBER_OF_CELL_SHAPES
};
@ -58,6 +69,10 @@ struct CellShapeTagCheck : std::false_type
{
};
/// Convert VTK-m tag to VTK-c tag
template <typename VtkmCellShapeTag>
struct CellShapeTagVtkmToVtkc;
} // namespace internal
/// Checks that the argument is a proper cell shape tag. This is a handy
@ -94,6 +109,11 @@ struct CellShapeIdToTag
struct CellShapeTagCheck<vtkm::CellShapeTag##name> : std::true_type \
{ \
}; \
template <> \
struct CellShapeTagVtkmToVtkc<vtkm::CellShapeTag##name> \
{ \
using Type = lcl::name; \
}; \
} \
static inline VTKM_EXEC_CONT const char* GetCellShapeName(vtkm::CellShapeTag##name) \
{ \
@ -140,6 +160,35 @@ struct CellShapeTagGeneric
vtkm::UInt8 Id;
};
namespace internal
{
template <typename VtkmCellShapeTag>
VTKM_EXEC_CONT inline typename CellShapeTagVtkmToVtkc<VtkmCellShapeTag>::Type make_VtkcCellShapeTag(
const VtkmCellShapeTag&,
vtkm::IdComponent numPoints = 0)
{
using VtkcCellShapeTag = typename CellShapeTagVtkmToVtkc<VtkmCellShapeTag>::Type;
static_cast<void>(numPoints); // unused
return VtkcCellShapeTag{};
}
VTKM_EXEC_CONT
inline lcl::Polygon make_VtkcCellShapeTag(const vtkm::CellShapeTagPolygon&,
vtkm::IdComponent numPoints = 0)
{
return lcl::Polygon(numPoints);
}
VTKM_EXEC_CONT
inline lcl::Cell make_VtkcCellShapeTag(const vtkm::CellShapeTagGeneric& tag,
vtkm::IdComponent numPoints = 0)
{
return lcl::Cell(static_cast<std::int8_t>(tag.Id), numPoints);
}
} // namespace internal
#define vtkmGenericCellShapeMacroCase(cellShapeId, call) \
case vtkm::cellShapeId: \
{ \

138
vtkm/Deprecated.h Normal file

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

@ -150,6 +150,27 @@ struct ListTagTransform : detail::ListRoot
brigand::bind<Transform, brigand::_1>>;
};
/// A list tag that takes an existing ListTag and a predicate template that is applied to
/// each type in the ListTag. Any type in the ListTag that has a value element equal to true
/// (the equivalent of std::true_type), that item will be removed from the list. For example
/// the following type
///
/// ```cpp
/// vtkm::ListTagRemoveIf<vtkm::ListTagBase<int, float, long long, double>, std::is_integral>
/// ```
///
/// resolves to a ListTag that is equivalent to `vtkm::ListTag<float, double>` because
/// `std::is_integral<int>` and `std::is_integral<long long>` resolve to `std::true_type`
/// whereas `std::is_integral<float>` and `std::is_integral<double>` resolve to
/// `std::false_type`.
template <typename ListTag, template <typename> class Predicate>
struct ListTagRemoveIf : detail::ListRoot
{
VTKM_IS_LIST_TAG(ListTag);
using list = brigand::remove_if<internal::ListTagAsBrigandList<ListTag>,
brigand::bind<Predicate, 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.

@ -183,18 +183,18 @@ struct VTKM_NEVER_EXPORT VecTraits<const T> : VecTraits<T>
{
};
#if defined(VTKM_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
#if defined(VTKM_GCC) && (__GNUC__ <= 5)
namespace detail
{
template <typename NewT, vtkm::IdComponent Size>
struct VecReplaceComponentTypeGCC48
struct VecReplaceComponentTypeGCC4or5
{
using type = vtkm::Vec<NewT, Size>;
};
template <typename T, vtkm::IdComponent Size, typename NewT>
struct VecReplaceBaseComponentTypeGCC48
struct VecReplaceBaseComponentTypeGCC4or5
{
using type =
vtkm::Vec<typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<NewT>, Size>;
@ -274,12 +274,12 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
/// This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
/// is vtkm::Vec<T2, N>.
///@{
#if defined(VTKM_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
// Silly workaround for bug in GCC 4.8
#if defined(VTKM_GCC) && (__GNUC__ <= 5)
// Silly workaround for bug in GCC <= 5
template <typename NewComponentType>
using ReplaceComponentType =
typename detail::VecReplaceComponentTypeGCC48<NewComponentType, Size>::type;
#else // !GCC 4.8
typename detail::VecReplaceComponentTypeGCC4or5<NewComponentType, Size>::type;
#else // !GCC <= 5
template <typename NewComponentType>
using ReplaceComponentType = vtkm::Vec<NewComponentType, Size>;
#endif
@ -291,12 +291,12 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
/// is recursive for nested types. For example,
/// VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is Vec<Vec<T2, M>, N>.
///@{
#if defined(VTKM_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
// Silly workaround for bug in GCC 4.8
#if defined(VTKM_GCC) && (__GNUC__ <= 5)
// Silly workaround for bug in GCC <= 5
template <typename NewComponentType>
using ReplaceBaseComponentType =
typename detail::VecReplaceBaseComponentTypeGCC48<T, Size, NewComponentType>::type;
#else // !GCC 4.8
typename detail::VecReplaceBaseComponentTypeGCC4or5<T, Size, NewComponentType>::type;
#else // !GCC <= 5
template <typename NewComponentType>
using ReplaceBaseComponentType = vtkm::Vec<
typename vtkm::VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>,

@ -594,7 +594,7 @@ struct Algorithm
template <typename WordType>
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word)
{
FillBitField(vtkm::cont::DeviceAdapterTagAny{}, bits, word);
Fill(vtkm::cont::DeviceAdapterTagAny{}, bits, word);
}
template <typename T, typename S>

@ -57,24 +57,18 @@ class VTKM_CONT_EXPORT ArrayHandleBase
/// with C++11 type_traits.
///
template <typename T, typename StorageTag>
struct IsValidArrayHandle
: std::integral_constant<bool,
!(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>
{
};
using IsValidArrayHandle =
std::integral_constant<bool,
!(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>;
/// Checks to see if the given type and storage forms a invalid array handle
/// (some storage objects cannot support all types). This check is compatible
/// with C++11 type_traits.
///
template <typename T, typename StorageTag>
struct IsInValidArrayHandle
: std::integral_constant<bool,
(std::is_base_of<vtkm::cont::internal::UndefinedStorage,
vtkm::cont::internal::Storage<T, StorageTag>>::value)>
{
};
using IsInValidArrayHandle =
std::integral_constant<bool, !IsValidArrayHandle<T, StorageTag>::value>;
/// Checks to see if the ArrayHandle allows writing, as some ArrayHandles
/// (Implicit) don't support writing. These will be defined as either

@ -17,6 +17,8 @@
#include <vtkmtaotuple/include/Tuple.h>
#include <vtkm/internal/brigand.hpp>
#include <type_traits>
namespace vtkm
@ -373,11 +375,18 @@ struct ArraySizeValidator
}
};
template <typename PortalList>
using AllPortalsAreWritable =
typename brigand::all<PortalList,
brigand::bind<vtkm::internal::PortalSupportsSets, brigand::_1>>::type;
} // end namespace compvec
template <typename PortalTuple>
class VTKM_ALWAYS_EXPORT ArrayPortalCompositeVector
{
using Writable = compvec::AllPortalsAreWritable<PortalTuple>;
public:
using ValueType = typename compvec::GetValueType<PortalTuple>::ValueType;
@ -459,8 +468,9 @@ public:
return result;
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
SetImpl<0, PortalTuple>::Exec(this->Portals, value, index);
}

@ -22,6 +22,10 @@ namespace internal
template <typename PortalType1, typename PortalType2>
class VTKM_ALWAYS_EXPORT ArrayPortalConcatenate
{
using WritableP1 = vtkm::internal::PortalSupportsSets<PortalType1>;
using WritableP2 = vtkm::internal::PortalSupportsSets<PortalType2>;
using Writable = std::integral_constant<bool, WritableP1::value && WritableP2::value>;
public:
using ValueType = typename PortalType1::ValueType;
@ -58,18 +62,27 @@ public:
ValueType Get(vtkm::Id index) const
{
if (index < this->portal1.GetNumberOfValues())
{
return this->portal1.Get(index);
}
else
{
return this->portal2.Get(index - this->portal1.GetNumberOfValues());
}
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
if (index < this->portal1.GetNumberOfValues())
{
this->portal1.Set(index, value);
}
else
{
this->portal2.Set(index - this->portal1.GetNumberOfValues(), value);
}
}
VTKM_EXEC_CONT

@ -20,10 +20,19 @@
#include <vtkm/internal/brigand.hpp>
#include <vtkmtaotuple/include/Tuple.h>
#include <vtkmtaotuple/include/tao/seq/make_integer_sequence.hpp>
#include <type_traits>
#include <utility>
// MSVC and CUDA and Xcode < 10 and Clang < 5 have issues with tao integer sequences
#if defined(VTKM_MSVC) || defined(VTKM_CUDA_DEVICE_PASS) || \
(defined(__apple_build_version__) && (__apple_build_version__ < 10000000)) || \
(defined(VTKM_CLANG) && (__clang_major__ < 5))
#define VTKM_USE_BRIGAND_SEQ
#endif
namespace vtkm
{
namespace cont
@ -67,9 +76,9 @@ public:
VTKM_CONT
ArrayPortalDecorator(FunctorType func, InverseFunctorType iFunc, vtkm::Id numValues)
: Functor{ func }
, InverseFunctor{ iFunc }
, NumberOfValues{ numValues }
: Functor(func)
, InverseFunctor(iFunc)
, NumberOfValues(numValues)
{
}
@ -349,8 +358,12 @@ struct DecoratorStorageTraits
using ArrayTupleType = vtkmstd::tuple<ArrayTs...>;
// size_t integral constants that index ArrayTs:
// size_t integral constants that index ArrayTs:
#ifdef VTKM_USE_BRIGAND_SEQ
using IndexList = brigand::make_sequence<brigand::size_t<0>, sizeof...(ArrayTs)>;
#else // VTKM_USE_BRIGAND_SEQ
using IndexList = tao::seq::make_index_sequence<sizeof...(ArrayTs)>;
#endif // VTKM_USE_BRIGAND_SEQ
// Portal lists:
// NOTE we have to pass the parameter pack here instead of using ArrayList
@ -429,6 +442,7 @@ struct DecoratorStorageTraits
return { impl.CreateFunctor(portals...), impl.CreateInverseFunctor(portals...), numVals };
}
#ifdef VTKM_USE_BRIGAND_SEQ
// Portal construction methods. These actually create portals.
template <template <typename...> class List, typename... Indices>
VTKM_CONT static PortalControlType MakePortalControl(const DecoratorImplT& impl,
@ -508,6 +522,62 @@ struct DecoratorStorageTraits
// note in MakePortalControl.
GetPortalOutput(vtkmstd::get<Indices{}.value>(arrays), dev)...);
}
#else // VTKM_USE_BRIGAND_SEQ
// Portal construction methods. These actually create portals.
template <template <typename, std::size_t...> class List, std::size_t... Indices>
VTKM_CONT static PortalControlType MakePortalControl(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>)
{
return CreatePortalDecorator<PortalControlType>(
numValues, impl, GetPortalControl(vtkmstd::get<Indices>(arrays))...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices>
VTKM_CONT static PortalConstControlType MakePortalConstControl(const DecoratorImplT& impl,
const ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>)
{
return CreatePortalDecorator<PortalConstControlType>(
numValues, impl, GetPortalConstControl(vtkmstd::get<Indices>(arrays))...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
VTKM_CONT static PortalConstExecutionType<Device> MakePortalInput(const DecoratorImplT& impl,
const ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
{
return CreatePortalDecorator<PortalConstExecutionType<Device>>(
numValues, impl, GetPortalInput(vtkmstd::get<Indices>(arrays), dev)...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
VTKM_CONT static PortalExecutionType<Device> MakePortalInPlace(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues, impl, GetPortalInPlace(vtkmstd::get<Indices>(arrays), dev)...);
}
template <template <typename, std::size_t...> class List, std::size_t... Indices, typename Device>
VTKM_CONT static PortalExecutionType<Device> MakePortalOutput(const DecoratorImplT& impl,
ArrayTupleType& arrays,
vtkm::Id numValues,
List<std::size_t, Indices...>,
Device dev)
{
return CreatePortalDecorator<PortalExecutionType<Device>>(
numValues, impl, GetPortalOutput(vtkmstd::get<Indices>(arrays), dev)...);
}
#endif // VTKM_USE_BRIGAND_SEQ
};
} // end namespace decor
@ -538,7 +608,7 @@ public:
VTKM_CONT
Storage(const DecoratorImplT& impl, const ArrayTupleType& arrayTuple, vtkm::Id numValues)
: Implementation{ impl }
: Implementation(impl)
, ArrayTuple{ arrayTuple }
, NumberOfValues(numValues)
, Valid{ true }
@ -824,4 +894,6 @@ make_ArrayHandleDecorator(vtkm::Id numValues, DecoratorImplT&& f, ArrayTs&&... a
}
} // namespace vtkm::cont
#undef VTKM_USE_BRIGAND_SEQ
#endif //vtk_m_ArrayHandleDecorator_h

@ -23,6 +23,8 @@ namespace internal
template <typename PortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalExtractComponent
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using VectorType = typename PortalType::ValueType;
using Traits = vtkm::VecTraits<VectorType>;
@ -49,6 +51,9 @@ public:
{
}
ArrayPortalExtractComponent& operator=(const ArrayPortalExtractComponent& src) = default;
ArrayPortalExtractComponent& operator=(ArrayPortalExtractComponent&& src) = default;
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); }
@ -58,8 +63,9 @@ public:
return Traits::GetComponent(this->Portal.Get(index), this->Component);
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
VectorType vec = this->Portal.Get(index);
Traits::SetComponent(vec, this->Component, value);

@ -25,6 +25,8 @@ namespace internal
template <typename PortalType, vtkm::IdComponent N_COMPONENTS>
class VTKM_ALWAYS_EXPORT ArrayPortalGroupVec
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
static constexpr vtkm::IdComponent NUM_COMPONENTS = N_COMPONENTS;
using SourcePortalType = PortalType;
@ -79,8 +81,9 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
vtkm::Id sourceIndex = index * NUM_COMPONENTS;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)

@ -24,6 +24,8 @@ namespace internal
template <typename IndexPortalType, typename ValuePortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalPermutation
{
using Writable = vtkm::internal::PortalSupportsSets<ValuePortalType>;
public:
using ValueType = typename ValuePortalType::ValueType;
@ -69,8 +71,9 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC void Set(vtkm::Id index, const ValueType& value) const
{
vtkm::Id permutedIndex = this->IndexPortal.Get(index);
this->ValuePortal.Set(permutedIndex, value);

@ -26,6 +26,8 @@ namespace internal
template <typename PortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalReverse
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using ValueType = typename PortalType::ValueType;
@ -56,8 +58,9 @@ public:
return this->portal.Get(portal.GetNumberOfValues() - index - 1);
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->portal.Set(portal.GetNumberOfValues() - index - 1, value);
}

@ -23,6 +23,8 @@ namespace internal
template <typename P>
class VTKM_ALWAYS_EXPORT ArrayPortalStreaming
{
using Writable = vtkm::internal::PortalSupportsSets<P>;
public:
using PortalType = P;
using ValueType = typename PortalType::ValueType;
@ -66,8 +68,9 @@ public:
return this->InputPortal.Get(this->BlockIndex * this->BlockSize + index);
}
VTKM_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->InputPortal.Set(this->BlockIndex * this->BlockSize + index, value);
}

@ -117,6 +117,7 @@ template <typename PortalType, typename ArrayHandleType, vtkm::IdComponent OutSi
class VTKM_ALWAYS_EXPORT ArrayPortalSwizzle
{
using Traits = internal::ArrayHandleSwizzleTraits<ArrayHandleType, OutSize>;
using Writable = vtkm::internal::PortalSupportsSets<PortalType>;
public:
using MapType = typename Traits::MapType;
@ -143,6 +144,9 @@ public:
{
}
ArrayPortalSwizzle& operator=(const ArrayPortalSwizzle& src) = default;
ArrayPortalSwizzle& operator=(ArrayPortalSwizzle&& src) = default;
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); }
@ -154,8 +158,9 @@ public:
return result;
}
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
if (Traits::AllCompsUsed)
{ // No need to prefetch the value, all values overwritten

@ -90,16 +90,6 @@ public:
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const { return this->Functor(this->Portal.Get(index)); }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
{
#if !(defined(VTKM_MSVC) && defined(VTKM_CUDA))
VTKM_ASSERT(false &&
"Cannot write to read-only transform array. (No inverse transform given.)");
#endif
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
const PortalType& GetPortal() const { return this->Portal; }
@ -120,6 +110,8 @@ template <typename ValueType_,
class VTKM_ALWAYS_EXPORT ArrayPortalTransform
: public ArrayPortalTransform<ValueType_, PortalType_, FunctorType_, NullFunctorType>
{
using Writable = vtkm::internal::PortalSupportsSets<PortalType_>;
public:
using Superclass = ArrayPortalTransform<ValueType_, PortalType_, FunctorType_, NullFunctorType>;
using PortalType = PortalType_;
@ -147,11 +139,11 @@ public:
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
using call_supported_t = typename vtkm::internal::PortalSupportsSets<PortalType>::type;
this->Set(call_supported_t(), index, value);
this->Portal.Set(index, this->InverseFunctor(value));
}
VTKM_SUPPRESS_EXEC_WARNINGS
@ -160,14 +152,6 @@ 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 {}
};
}
}

@ -26,6 +26,8 @@ namespace internal
template <typename TargetPortalType>
class ArrayPortalView
{
using Writable = vtkm::internal::PortalSupportsSets<TargetPortalType>;
public:
using ValueType = typename TargetPortalType::ValueType;
@ -59,8 +61,9 @@ public:
ValueType Get(vtkm::Id index) const { return this->TargetPortal.Get(index + this->StartIndex); }
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
this->TargetPortal.Set(index + this->StartIndex, value);
}

@ -26,6 +26,14 @@ namespace internal
template <typename ValueType_, typename PortalTypeFirst_, typename PortalTypeSecond_>
class ArrayPortalZip
{
using ReadableP1 = vtkm::internal::PortalSupportsGets<PortalTypeFirst_>;
using ReadableP2 = vtkm::internal::PortalSupportsGets<PortalTypeSecond_>;
using WritableP1 = vtkm::internal::PortalSupportsSets<PortalTypeFirst_>;
using WritableP2 = vtkm::internal::PortalSupportsSets<PortalTypeSecond_>;
using Readable = std::integral_constant<bool, ReadableP1::value && ReadableP2::value>;
using Writable = std::integral_constant<bool, WritableP1::value && WritableP2::value>;
public:
using ValueType = ValueType_;
using T = typename ValueType::FirstType;
@ -64,23 +72,19 @@ public:
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->PortalFirst.GetNumberOfValues(); }
VTKM_EXEC
ValueType Get(vtkm::Id index) const
template <typename Readable_ = Readable,
typename = typename std::enable_if<Readable_::value>::type>
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const noexcept
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsGets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsGets<PortalTypeSecond>::type;
return vtkm::make_Pair(this->GetFirst(call_supported_t1(), index),
this->GetSecond(call_supported_t2(), index));
return vtkm::make_Pair(this->PortalFirst.Get(index), this->PortalSecond.Get(index));
}
VTKM_EXEC
void Set(vtkm::Id index, const ValueType& value) const
template <typename Writable_ = Writable,
typename = typename std::enable_if<Writable_::value>::type>
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const noexcept
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsSets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsSets<PortalTypeSecond>::type;
this->SetFirst(call_supported_t1(), index, value.first);
this->SetSecond(call_supported_t2(), index, value.second);
this->PortalFirst.Set(index, value.first);
this->PortalSecond.Set(index, value.second);
}
VTKM_EXEC_CONT
@ -90,28 +94,6 @@ public:
const PortalTypeSecond& GetSecondPortal() const { return this->PortalSecond; }
private:
VTKM_EXEC inline T GetFirst(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalFirst.Get(index);
}
VTKM_EXEC inline T GetFirst(std::false_type, vtkm::Id) const noexcept { return T{}; }
VTKM_EXEC inline U GetSecond(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalSecond.Get(index);
}
VTKM_EXEC inline U GetSecond(std::false_type, vtkm::Id) const noexcept { return U{}; }
VTKM_EXEC inline void SetFirst(std::true_type, vtkm::Id index, const T& value) const noexcept
{
this->PortalFirst.Set(index, value);
}
VTKM_EXEC inline void SetFirst(std::false_type, vtkm::Id, const T&) const noexcept {}
VTKM_EXEC inline void SetSecond(std::true_type, vtkm::Id index, const U& value) const noexcept
{
this->PortalSecond.Set(index, value);
}
VTKM_EXEC inline void SetSecond(std::false_type, vtkm::Id, const U&) const noexcept {}
PortalTypeFirst PortalFirst;
PortalTypeSecond PortalSecond;
};

@ -45,6 +45,12 @@ namespace cont
/// Although portals are defined in the execution environment, they are also
/// used in the control environment for accessing data on the host.
///
/// Since utilities like IsWritableArrayHandle checks for the existence of a Set
/// method on a portal, if the portal is backed by a read-only ArrayHandle, the
/// Set method must not be defined. If the portal may or may not be writable
/// (e.g., ArrayHandleCast may be casting a read-only OR read-write array), the
/// Set method may be conditionally removed using SFINAE.
///
template <typename T>
class ArrayPortal
{
@ -65,8 +71,7 @@ public:
ValueType Get(vtkm::Id index) const;
/// Sets a value in the array. If it is not possible to set a value in the
/// array, this method may error out (for example with a VTKM_ASSERT). In
/// this case the behavior is undefined.
/// array, this method must not be defined.
///
VTKM_EXEC_CONT
void Set(vtkm::Id index, const ValueType& value) const;

@ -211,7 +211,7 @@ if(TARGET vtkm::openmp)
endif()
target_link_libraries(vtkm_cont PUBLIC vtkm_compiler_flags ${backends})
target_link_libraries(vtkm_cont PUBLIC vtkm_taotuple vtkm_optionparser vtkm_diy)
target_link_libraries(vtkm_cont PUBLIC vtkm_taotuple vtkm_optionparser vtkm_diy vtkm_lcl)
if(TARGET vtkm_loguru)
target_link_libraries(vtkm_cont PRIVATE vtkm_loguru)
endif()

@ -29,7 +29,7 @@ template <vtkm::IdComponent>
class CellSetStructured;
template <typename T>
class CellSetSingleType;
template <typename T, typename S, typename U, typename V>
template <typename T, typename S, typename U>
class CellSetExplicit;
template <typename T, typename S>
class CellSetPermutation;
@ -88,10 +88,8 @@ void CastAndCall(const vtkm::cont::CellSetSingleType<ConnectivityStorageTag>& ce
/// A specialization of CastAndCall for basic CellSetExplicit types,
/// Since the type is already known no deduction is needed.
/// This specialization is used to simplify numerous worklet algorithms
template <typename T, typename S, typename U, typename V, typename Functor, typename... Args>
void CastAndCall(const vtkm::cont::CellSetExplicit<T, S, U, V>& cellset,
Functor&& f,
Args&&... args)
template <typename T, typename S, typename U, typename Functor, typename... Args>
void CastAndCall(const vtkm::cont::CellSetExplicit<T, S, U>& cellset, Functor&& f, Args&&... args)
{
f(cellset, std::forward<Args>(args)...);
}

@ -19,7 +19,6 @@ namespace cont
template class VTKM_CONT_EXPORT CellSetExplicit<>; // default
template class VTKM_CONT_EXPORT
CellSetExplicit<typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag,
VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>;
}

@ -12,8 +12,11 @@
#include <vtkm/CellShape.h>
#include <vtkm/TopologyElementTag.h>
#include <vtkm/cont/ArrayGetValues.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleDecorator.h>
#include <vtkm/cont/CellSet.h>
#include <vtkm/cont/internal/ConnectivityExplicitInternals.h>
#include <vtkm/exec/ConnectivityExplicit.h>
@ -34,14 +37,35 @@ struct CellSetExplicitConnectivityChooser
using ConnectivityType = vtkm::cont::internal::ConnectivityExplicitInternals<>;
};
// Used with ArrayHandleDecorator to recover the NumIndices array from the
// offsets.
struct NumIndicesDecorator
{
template <typename OffsetsPortal>
struct Functor
{
OffsetsPortal Offsets;
VTKM_EXEC_CONT
vtkm::IdComponent operator()(vtkm::Id cellId) const
{
return static_cast<vtkm::IdComponent>(this->Offsets.Get(cellId + 1) -
this->Offsets.Get(cellId));
}
};
template <typename OffsetsPortal>
static VTKM_CONT Functor<typename std::decay<OffsetsPortal>::type> CreateFunctor(
OffsetsPortal&& portal)
{
return { std::forward<OffsetsPortal>(portal) };
}
};
} // namespace detail
#ifndef VTKM_DEFAULT_SHAPE_STORAGE_TAG
#define VTKM_DEFAULT_SHAPE_STORAGE_TAG VTKM_DEFAULT_STORAGE_TAG
#endif
#ifndef VTKM_DEFAULT_NUM_INDICES_STORAGE_TAG
#define VTKM_DEFAULT_NUM_INDICES_STORAGE_TAG VTKM_DEFAULT_STORAGE_TAG
#ifndef VTKM_DEFAULT_SHAPES_STORAGE_TAG
#define VTKM_DEFAULT_SHAPES_STORAGE_TAG VTKM_DEFAULT_STORAGE_TAG
#endif
#ifndef VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG
@ -52,51 +76,89 @@ struct CellSetExplicitConnectivityChooser
#define VTKM_DEFAULT_OFFSETS_STORAGE_TAG VTKM_DEFAULT_STORAGE_TAG
#endif
template <typename ShapeStorageTag = VTKM_DEFAULT_SHAPE_STORAGE_TAG,
typename NumIndicesStorageTag = VTKM_DEFAULT_NUM_INDICES_STORAGE_TAG,
template <typename S1, typename S2>
void ConvertNumIndicesToOffsets(const vtkm::cont::ArrayHandle<vtkm::Id, S1>& numIndices,
vtkm::cont::ArrayHandle<vtkm::Id, S2>& offsets)
{
vtkm::cont::Algorithm::ScanExtended(numIndices, offsets);
}
template <typename T, typename S1, typename S2>
void ConvertNumIndicesToOffsets(const vtkm::cont::ArrayHandle<T, S1>& numIndices,
vtkm::cont::ArrayHandle<vtkm::Id, S2>& offsets)
{
const auto castCounts = vtkm::cont::make_ArrayHandleCast<vtkm::Id>(numIndices);
ConvertNumIndicesToOffsets(castCounts, offsets);
}
template <typename T, typename S1, typename S2>
void ConvertNumIndicesToOffsets(const vtkm::cont::ArrayHandle<T, S1>& numIndices,
vtkm::cont::ArrayHandle<vtkm::Id, S2>& offsets,
vtkm::Id& connectivitySize /* outparam */)
{
ConvertNumIndicesToOffsets(numIndices, offsets);
connectivitySize = vtkm::cont::ArrayGetValue(offsets.GetNumberOfValues() - 1, offsets);
}
template <typename T, typename S>
vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumIndicesToOffsets(
const vtkm::cont::ArrayHandle<T, S>& numIndices)
{
vtkm::cont::ArrayHandle<vtkm::Id> offsets;
ConvertNumIndicesToOffsets(numIndices, offsets);
return offsets;
}
template <typename T, typename S>
vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumIndicesToOffsets(
const vtkm::cont::ArrayHandle<T, S>& numIndices,
vtkm::Id& connectivityLength /* outparam */)
{
vtkm::cont::ArrayHandle<vtkm::Id> offsets;
ConvertNumIndicesToOffsets(numIndices, offsets, connectivityLength);
return offsets;
}
template <typename ShapesStorageTag = VTKM_DEFAULT_SHAPES_STORAGE_TAG,
typename ConnectivityStorageTag = VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
typename OffsetsStorageTag = VTKM_DEFAULT_OFFSETS_STORAGE_TAG>
class VTKM_ALWAYS_EXPORT CellSetExplicit : public CellSet
{
using Thisclass = CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>;
using Thisclass = CellSetExplicit<ShapesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>;
template <typename VisitTopology, typename IncidentTopology>
struct ConnectivityChooser
{
using ConnectivityType =
typename detail::CellSetExplicitConnectivityChooser<Thisclass,
VisitTopology,
IncidentTopology>::ConnectivityType;
private:
using Chooser = typename detail::CellSetExplicitConnectivityChooser<Thisclass,
VisitTopology,
IncidentTopology>;
using ShapeArrayType = typename ConnectivityType::ShapeArrayType;
using NumIndicesArrayType = typename ConnectivityType::NumIndicesArrayType;
public:
using ConnectivityType = typename Chooser::ConnectivityType;
using ShapesArrayType = typename ConnectivityType::ShapesArrayType;
using ConnectivityArrayType = typename ConnectivityType::ConnectivityArrayType;
using IndexOffsetArrayType = typename ConnectivityType::IndexOffsetArrayType;
using OffsetsArrayType = typename ConnectivityType::OffsetsArrayType;
using NumIndicesArrayType =
vtkm::cont::ArrayHandleDecorator<detail::NumIndicesDecorator, OffsetsArrayType>;
};
using VisitCellsWithPointsInternalsType =
typename ConnectivityChooser<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint>::ConnectivityType;
using ConnTypes =
ConnectivityChooser<vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint>;
using RConnTypes =
ConnectivityChooser<vtkm::TopologyElementTagPoint, vtkm::TopologyElementTagCell>;
using VisitPointsWithCellsInternalsType =
typename ConnectivityChooser<vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell>::ConnectivityType;
using CellPointIdsType = typename ConnTypes::ConnectivityType;
using PointCellIdsType = typename RConnTypes::ConnectivityType;
public:
using SchedulingRangeType = vtkm::Id;
//point to cell is used when iterating cells and asking for point properties
using VisitCellsWithPointsConnectivityType =
ConnectivityChooser<vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint>;
using ShapeArrayType = typename VisitCellsWithPointsConnectivityType::ShapeArrayType;
using NumIndicesArrayType = typename VisitCellsWithPointsConnectivityType::NumIndicesArrayType;
using ConnectivityArrayType =
typename VisitCellsWithPointsConnectivityType::ConnectivityArrayType;
using IndexOffsetArrayType = typename VisitCellsWithPointsConnectivityType::IndexOffsetArrayType;
using ShapesArrayType = typename CellPointIdsType::ShapesArrayType;
using ConnectivityArrayType = typename CellPointIdsType::ConnectivityArrayType;
using OffsetsArrayType = typename CellPointIdsType::OffsetsArrayType;
using NumIndicesArrayType = typename ConnTypes::NumIndicesArrayType;
VTKM_CONT CellSetExplicit();
VTKM_CONT CellSetExplicit(const Thisclass& src);
@ -105,28 +167,29 @@ public:
VTKM_CONT Thisclass& operator=(const Thisclass& src);
VTKM_CONT Thisclass& operator=(Thisclass&& src) noexcept;
virtual ~CellSetExplicit();
VTKM_CONT virtual ~CellSetExplicit();
vtkm::Id GetNumberOfCells() const override;
vtkm::Id GetNumberOfPoints() const override;
vtkm::Id GetNumberOfFaces() const override;
vtkm::Id GetNumberOfEdges() const override;
void PrintSummary(std::ostream& out) const override;
void ReleaseResourcesExecution() override;
VTKM_CONT vtkm::Id GetNumberOfCells() const override;
VTKM_CONT vtkm::Id GetNumberOfPoints() const override;
VTKM_CONT vtkm::Id GetNumberOfFaces() const override;
VTKM_CONT vtkm::Id GetNumberOfEdges() const override;
VTKM_CONT void PrintSummary(std::ostream& out) const override;
std::shared_ptr<CellSet> NewInstance() const override;
void DeepCopy(const CellSet* src) override;
VTKM_CONT void ReleaseResourcesExecution() override;
VTKM_CONT std::shared_ptr<CellSet> NewInstance() const override;
VTKM_CONT void DeepCopy(const CellSet* src) override;
VTKM_CONT vtkm::Id GetSchedulingRange(vtkm::TopologyElementTagCell) const;
VTKM_CONT vtkm::Id GetSchedulingRange(vtkm::TopologyElementTagPoint) const;
VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id cellIndex) const override;
void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const override;
VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id cellid) const override;
VTKM_CONT void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const override;
VTKM_CONT vtkm::UInt8 GetCellShape(vtkm::Id cellIndex) const override;
VTKM_CONT vtkm::UInt8 GetCellShape(vtkm::Id cellid) const override;
template <vtkm::IdComponent ItemTupleLength>
VTKM_CONT void GetIndices(vtkm::Id index, vtkm::Vec<vtkm::Id, ItemTupleLength>& ids) const;
template <vtkm::IdComponent NumIndices>
VTKM_CONT void GetIndices(vtkm::Id index, vtkm::Vec<vtkm::Id, NumIndices>& ids) const;
VTKM_CONT void GetIndices(vtkm::Id index, vtkm::cont::ArrayHandle<vtkm::Id>& ids) const;
@ -143,74 +206,69 @@ public:
/// the way you can fill the memory from another system without copying
VTKM_CONT
void Fill(vtkm::Id numPoints,
const vtkm::cont::ArrayHandle<vtkm::UInt8, ShapeStorageTag>& cellTypes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent, NumIndicesStorageTag>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::UInt8, ShapesStorageTag>& cellTypes,
const vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityStorageTag>& connectivity,
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& offsets =
vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>());
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& offsets);
template <typename DeviceAdapter, typename VisitTopology, typename IncidentTopology>
template <typename Device, typename VisitTopology, typename IncidentTopology>
struct ExecutionTypes
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapter);
private:
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
VTKM_IS_TOPOLOGY_ELEMENT_TAG(VisitTopology);
VTKM_IS_TOPOLOGY_ELEMENT_TAG(IncidentTopology);
using ConnectivityTypes = ConnectivityChooser<VisitTopology, IncidentTopology>;
using Chooser = ConnectivityChooser<VisitTopology, IncidentTopology>;
using ShapePortalType = typename ConnectivityTypes::ShapeArrayType::template ExecutionTypes<
DeviceAdapter>::PortalConst;
using IndicePortalType =
typename ConnectivityTypes::NumIndicesArrayType::template ExecutionTypes<
DeviceAdapter>::PortalConst;
using ConnectivityPortalType =
typename ConnectivityTypes::ConnectivityArrayType::template ExecutionTypes<
DeviceAdapter>::PortalConst;
using IndexOffsetPortalType =
typename ConnectivityTypes::IndexOffsetArrayType::template ExecutionTypes<
DeviceAdapter>::PortalConst;
using ShapesAT = typename Chooser::ShapesArrayType;
using ConnAT = typename Chooser::ConnectivityArrayType;
using OffsetsAT = typename Chooser::OffsetsArrayType;
using ExecObjectType = vtkm::exec::ConnectivityExplicit<ShapePortalType,
IndicePortalType,
ConnectivityPortalType,
IndexOffsetPortalType>;
using ShapesET = typename ShapesAT::template ExecutionTypes<Device>;
using ConnET = typename ConnAT::template ExecutionTypes<Device>;
using OffsetsET = typename OffsetsAT::template ExecutionTypes<Device>;
public:
using ShapesPortalType = typename ShapesET::PortalConst;
using ConnectivityPortalType = typename ConnET::PortalConst;
using OffsetsPortalType = typename OffsetsET::PortalConst;
using ExecObjectType =
vtkm::exec::ConnectivityExplicit<ShapesPortalType, ConnectivityPortalType, OffsetsPortalType>;
};
template <typename Device, typename VisitTopology, typename IncidentTopology>
typename ExecutionTypes<Device, VisitTopology, IncidentTopology>::ExecObjectType
VTKM_CONT typename ExecutionTypes<Device, VisitTopology, IncidentTopology>::ExecObjectType
PrepareForInput(Device, VisitTopology, IncidentTopology) const;
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT const typename ConnectivityChooser<VisitTopology, IncidentTopology>::ShapeArrayType&
VTKM_CONT const typename ConnectivityChooser<VisitTopology, IncidentTopology>::ShapesArrayType&
GetShapesArray(VisitTopology, IncidentTopology) const;
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::NumIndicesArrayType&
GetNumIndicesArray(VisitTopology, IncidentTopology) const;
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::ConnectivityArrayType&
GetConnectivityArray(VisitTopology, IncidentTopology) const;
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::IndexOffsetArrayType&
GetIndexOffsetArray(VisitTopology, IncidentTopology) const;
VTKM_CONT const typename ConnectivityChooser<VisitTopology, IncidentTopology>::OffsetsArrayType&
GetOffsetsArray(VisitTopology, IncidentTopology) const;
// Can be used to check if e.g. CellToPoint table is built.
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT bool HasConnectivity(VisitTopology from, IncidentTopology to) const
VTKM_CONT typename ConnectivityChooser<VisitTopology, IncidentTopology>::NumIndicesArrayType
GetNumIndicesArray(VisitTopology, IncidentTopology) const;
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT bool HasConnectivity(VisitTopology visit, IncidentTopology incident) const
{
return this->HasConnectivityImpl(from, to);
return this->HasConnectivityImpl(visit, incident);
}
// Can be used to reset a connectivity table, mostly useful for benchmarking.
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT void ResetConnectivity(VisitTopology from, IncidentTopology to)
VTKM_CONT void ResetConnectivity(VisitTopology visit, IncidentTopology incident)
{
this->ResetConnectivityImpl(from, to);
this->ResetConnectivityImpl(visit, incident);
}
protected:
@ -225,20 +283,20 @@ protected:
VTKM_CONT bool HasConnectivityImpl(vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint) const
{
return this->Data->VisitCellsWithPoints.ElementsValid;
return this->Data->CellPointIds.ElementsValid;
}
VTKM_CONT bool HasConnectivityImpl(vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell) const
{
return this->Data->VisitPointsWithCells.ElementsValid;
return this->Data->PointCellIds.ElementsValid;
}
VTKM_CONT void ResetConnectivityImpl(vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint)
{
// Reset entire cell set
this->Data->VisitCellsWithPoints = VisitCellsWithPointsInternalsType{};
this->Data->VisitPointsWithCells = VisitPointsWithCellsInternalsType{};
this->Data->CellPointIds = CellPointIdsType{};
this->Data->PointCellIds = PointCellIdsType{};
this->Data->ConnectivityAdded = -1;
this->Data->NumberOfCellsAdded = -1;
this->Data->NumberOfPoints = 0;
@ -246,15 +304,15 @@ protected:
VTKM_CONT void ResetConnectivityImpl(vtkm::TopologyElementTagPoint, vtkm::TopologyElementTagCell)
{
this->Data->VisitPointsWithCells = VisitPointsWithCellsInternalsType{};
this->Data->PointCellIds = PointCellIdsType{};
}
// Store internals in a shared pointer so shallow copies stay consistent.
// See #2268.
struct Internals
{
VisitCellsWithPointsInternalsType VisitCellsWithPoints;
VisitPointsWithCellsInternalsType VisitPointsWithCells;
CellPointIdsType CellPointIds;
PointCellIdsType PointCellIds;
// These are used in the AddCell and related methods to incrementally add
// cells. They need to be protected as subclasses of CellSetExplicit
@ -275,42 +333,45 @@ protected:
std::shared_ptr<Internals> Data;
private:
const VisitCellsWithPointsInternalsType& GetConnectivity(vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint) const
VTKM_CONT
const CellPointIdsType& GetConnectivity(vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint) const
{
return this->Data->VisitCellsWithPoints;
return this->Data->CellPointIds;
}
const VisitCellsWithPointsInternalsType& GetConnectivity(vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint)
VTKM_CONT
const CellPointIdsType& GetConnectivity(vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint)
{
return this->Data->VisitCellsWithPoints;
return this->Data->CellPointIds;
}
const VisitPointsWithCellsInternalsType& GetConnectivity(vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell) const
VTKM_CONT
const PointCellIdsType& GetConnectivity(vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell) const
{
return this->Data->VisitPointsWithCells;
return this->Data->PointCellIds;
}
const VisitPointsWithCellsInternalsType& GetConnectivity(vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell)
VTKM_CONT
const PointCellIdsType& GetConnectivity(vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell)
{
return this->Data->VisitPointsWithCells;
return this->Data->PointCellIds;
}
};
namespace detail
{
template <typename Storage1, typename Storage2, typename Storage3, typename Storage4>
struct CellSetExplicitConnectivityChooser<
vtkm::cont::CellSetExplicit<Storage1, Storage2, Storage3, Storage4>,
vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint>
template <typename Storage1, typename Storage2, typename Storage3>
struct CellSetExplicitConnectivityChooser<vtkm::cont::CellSetExplicit<Storage1, Storage2, Storage3>,
vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint>
{
using ConnectivityType =
vtkm::cont::internal::ConnectivityExplicitInternals<Storage1, Storage2, Storage3, Storage4>;
vtkm::cont::internal::ConnectivityExplicitInternals<Storage1, Storage2, Storage3>;
};
template <typename CellSetType>
@ -332,7 +393,6 @@ struct CellSetExplicitConnectivityChooser<CellSetType,
extern template class VTKM_CONT_TEMPLATE_EXPORT CellSetExplicit<>; // default
extern template class VTKM_CONT_TEMPLATE_EXPORT CellSetExplicit<
typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag,
VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>; // CellSetSingleType base
#endif
@ -348,17 +408,15 @@ namespace vtkm
namespace cont
{
template <typename ShapeST, typename CountST, typename ConnectivityST, typename OffsetST>
struct SerializableTypeString<
vtkm::cont::CellSetExplicit<ShapeST, CountST, ConnectivityST, OffsetST>>
template <typename SST, typename CST, typename OST>
struct SerializableTypeString<vtkm::cont::CellSetExplicit<SST, CST, OST>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "CS_Explicit<" +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::UInt8, ShapeST>>::Get() + "_ST," +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::IdComponent, CountST>>::Get() + "_ST," +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityST>>::Get() + "_ST," +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::Id, OffsetST>>::Get() + "_ST>";
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::UInt8, SST>>::Get() + "_ST," +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::Id, CST>>::Get() + "_ST," +
SerializableTypeString<vtkm::cont::ArrayHandle<vtkm::Id, OST>>::Get() + "_ST>";
return name;
}
@ -369,11 +427,11 @@ struct SerializableTypeString<
namespace mangled_diy_namespace
{
template <typename ShapeST, typename CountST, typename ConnectivityST, typename OffsetST>
struct Serialization<vtkm::cont::CellSetExplicit<ShapeST, CountST, ConnectivityST, OffsetST>>
template <typename SST, typename CST, typename OST>
struct Serialization<vtkm::cont::CellSetExplicit<SST, CST, OST>>
{
private:
using Type = vtkm::cont::CellSetExplicit<ShapeST, CountST, ConnectivityST, OffsetST>;
using Type = vtkm::cont::CellSetExplicit<SST, CST, OST>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const Type& cs)
@ -381,29 +439,25 @@ public:
vtkmdiy::save(bb, cs.GetNumberOfPoints());
vtkmdiy::save(
bb, cs.GetShapesArray(vtkm::TopologyElementTagCell{}, vtkm::TopologyElementTagPoint{}));
vtkmdiy::save(
bb, cs.GetNumIndicesArray(vtkm::TopologyElementTagCell{}, vtkm::TopologyElementTagPoint{}));
vtkmdiy::save(
bb, cs.GetConnectivityArray(vtkm::TopologyElementTagCell{}, vtkm::TopologyElementTagPoint{}));
vtkmdiy::save(
bb, cs.GetIndexOffsetArray(vtkm::TopologyElementTagCell{}, vtkm::TopologyElementTagPoint{}));
bb, cs.GetOffsetsArray(vtkm::TopologyElementTagCell{}, vtkm::TopologyElementTagPoint{}));
}
static VTKM_CONT void load(BinaryBuffer& bb, Type& cs)
{
vtkm::Id numberOfPoints = 0;
vtkmdiy::load(bb, numberOfPoints);
vtkm::cont::ArrayHandle<vtkm::UInt8, ShapeST> shapes;
vtkm::cont::ArrayHandle<vtkm::UInt8, SST> shapes;
vtkmdiy::load(bb, shapes);
vtkm::cont::ArrayHandle<vtkm::IdComponent, CountST> counts;
vtkmdiy::load(bb, counts);
vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityST> connectivity;
vtkm::cont::ArrayHandle<vtkm::Id, CST> connectivity;
vtkmdiy::load(bb, connectivity);
vtkm::cont::ArrayHandle<vtkm::Id, OffsetST> offsets;
vtkm::cont::ArrayHandle<vtkm::Id, OST> offsets;
vtkmdiy::load(bb, offsets);
cs = Type{};
cs.Fill(numberOfPoints, shapes, counts, connectivity, offsets);
cs.Fill(numberOfPoints, shapes, connectivity, offsets);
}
};

@ -10,302 +10,267 @@
#ifndef vtk_m_cont_CellSetExplicit_hxx
#define vtk_m_cont_CellSetExplicit_hxx
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayGetValues.h>
#include <vtkm/cont/ArrayHandleDecorator.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/TryExecute.h>
// This file uses a lot of very verbose identifiers and the clang formatted
// code quickly becomes unreadable. Stick with manual formatting for now.
//
// clang-format off
namespace vtkm
{
namespace cont
{
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::CellSetExplicit()
template <typename SST, typename CST, typename OST>
VTKM_CONT
CellSetExplicit<SST, CST, OST>::CellSetExplicit()
: CellSet()
, Data(std::make_shared<Internals>())
{
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::CellSetExplicit(const Thisclass& src)
template <typename SST, typename CST, typename OST>
VTKM_CONT
CellSetExplicit<SST, CST, OST>::CellSetExplicit(const Thisclass& src)
: CellSet(src)
, Data(src.Data)
{
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::CellSetExplicit(Thisclass &&src) noexcept
: CellSet(std::forward<CellSet>(src)),
Data(std::move(src.Data))
template <typename SST, typename CST, typename OST>
VTKM_CONT
CellSetExplicit<SST, CST, OST>::CellSetExplicit(Thisclass &&src) noexcept
: CellSet(std::forward<CellSet>(src))
, Data(std::move(src.Data))
{
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT auto
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
operator=(const Thisclass& src) -> Thisclass&
template <typename SST, typename CST, typename OST>
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>::operator=(const Thisclass& src)
-> Thisclass&
{
this->CellSet::operator=(src);
this->Data = src.Data;
return *this;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT auto
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
operator=(Thisclass&& src) noexcept -> Thisclass&
template <typename SST, typename CST, typename OST>
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>::operator=(Thisclass&& src) noexcept
-> Thisclass&
{
this->CellSet::operator=(std::forward<CellSet>(src));
this->Data = std::move(src.Data);
return *this;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
~CellSetExplicit()
// explicitly define instead of '=default' to workaround an intel compiler bug
// (see #179)
template <typename SST, typename CST, typename OST>
VTKM_CONT
CellSetExplicit<SST, CST, OST>::~CellSetExplicit()
{
// explicitly define instead of '=default' to workaround an intel compiler bug
// (see #179)
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::PrintSummary(std::ostream& out) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::PrintSummary(std::ostream& out) const
{
out << " ExplicitCellSet: " << std::endl;
out << " VisitCellsWithPoints: " << std::endl;
this->Data->VisitCellsWithPoints.PrintSummary(out);
out << " VisitPointsWithCells: " << std::endl;
this->Data->VisitPointsWithCells.PrintSummary(out);
out << " ExplicitCellSet:" << std::endl;
out << " CellPointIds:" << std::endl;
this->Data->CellPointIds.PrintSummary(out);
out << " PointCellIds:" << std::endl;
this->Data->PointCellIds.PrintSummary(out);
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetStorageTag>
void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetStorageTag>::ReleaseResourcesExecution()
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::ReleaseResourcesExecution()
{
this->Data->VisitCellsWithPoints.ReleaseResourcesExecution();
this->Data->VisitPointsWithCells.ReleaseResourcesExecution();
this->Data->CellPointIds.ReleaseResourcesExecution();
this->Data->PointCellIds.ReleaseResourcesExecution();
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
vtkm::Id CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetNumberOfCells() const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>::GetNumberOfCells() const
{
return this->Data->VisitCellsWithPoints.GetNumberOfElements();
return this->Data->CellPointIds.GetNumberOfElements();
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
vtkm::Id CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetNumberOfPoints() const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>::GetNumberOfPoints() const
{
return this->Data->NumberOfPoints;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
vtkm::Id CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetNumberOfFaces() const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>::GetNumberOfFaces() const
{
return -1;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
vtkm::Id CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetNumberOfEdges() const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>::GetNumberOfEdges() const
{
return -1;
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::GetCellPointIds(vtkm::Id cellId,
vtkm::Id* ptids) const
{
auto arrayWrapper = vtkm::cont::make_ArrayHandle(ptids, this->GetNumberOfPointsInCell(id));
this->GetIndices(id, arrayWrapper);
const auto offPortal = this->Data->CellPointIds.Offsets.GetPortalConstControl();
const vtkm::Id start = offPortal.Get(cellId);
const vtkm::Id end = offPortal.Get(cellId + 1);
const vtkm::IdComponent numIndices = static_cast<vtkm::IdComponent>(end - start);
auto connPortal = this->Data->CellPointIds.Connectivity.GetPortalConstControl();
for (vtkm::IdComponent i = 0; i < numIndices; i++)
{
ptids[i] = connPortal.Get(start + i);
}
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT vtkm::Id
CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetSchedulingRange(vtkm::TopologyElementTagCell) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>
::GetSchedulingRange(vtkm::TopologyElementTagCell) const
{
return this->GetNumberOfCells();
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT vtkm::Id
CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetSchedulingRange(vtkm::TopologyElementTagPoint) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::Id CellSetExplicit<SST, CST, OST>
::GetSchedulingRange(vtkm::TopologyElementTagPoint) const
{
return this->GetNumberOfPoints();
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT vtkm::IdComponent
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
GetNumberOfPointsInCell(vtkm::Id cellIndex) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::IdComponent CellSetExplicit<SST, CST, OST>
::GetNumberOfPointsInCell(vtkm::Id cellid) const
{
return this->Data->VisitCellsWithPoints.NumIndices.GetPortalConstControl().Get(cellIndex);
const auto portal = this->Data->CellPointIds.Offsets.GetPortalConstControl();
return static_cast<vtkm::IdComponent>(portal.Get(cellid + 1) -
portal.Get(cellid));
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT vtkm::UInt8 CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetCellShape(vtkm::Id cellIndex) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
vtkm::UInt8 CellSetExplicit<SST, CST, OST>
::GetCellShape(vtkm::Id cellid) const
{
return this->Data->VisitCellsWithPoints.Shapes.GetPortalConstControl().Get(cellIndex);
return this->Data->CellPointIds.Shapes.GetPortalConstControl().Get(cellid);
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <vtkm::IdComponent ItemTupleLength>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
GetIndices(vtkm::Id index, vtkm::Vec<vtkm::Id, ItemTupleLength>& ids) const
template <typename SST, typename CST, typename OST>
template <vtkm::IdComponent NumVecIndices>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::GetIndices(vtkm::Id cellId, vtkm::Vec<vtkm::Id, NumVecIndices>& ids) const
{
this->Data->VisitCellsWithPoints.BuildIndexOffsets(vtkm::cont::DeviceAdapterTagAny{});
vtkm::IdComponent numIndices = this->GetNumberOfPointsInCell(index);
vtkm::Id start = this->Data->VisitCellsWithPoints.IndexOffsets.GetPortalConstControl().Get(index);
for (vtkm::IdComponent i = 0; i < numIndices && i < ItemTupleLength; i++)
const auto offPortal = this->Data->CellPointIds.Offsets.GetPortalConstControl();
const vtkm::Id start = offPortal.Get(cellId);
const vtkm::Id end = offPortal.Get(cellId + 1);
const auto numCellIndices = static_cast<vtkm::IdComponent>(end - start);
const auto connPortal = this->Data->CellPointIds.Connectivity.GetPortalConstControl();
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Warn,
numCellIndices != NumVecIndices,
"GetIndices given a " << NumVecIndices
<< "-vec to fetch a cell with " << numCellIndices << "points. "
"Truncating result.");
const vtkm::IdComponent numIndices = vtkm::Min(NumVecIndices, numCellIndices);
for (vtkm::IdComponent i = 0; i < numIndices; i++)
{
ids[i] = this->Data->VisitCellsWithPoints.Connectivity.GetPortalConstControl().Get(start + i);
ids[i] = connPortal.Get(start + i);
}
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
GetIndices(vtkm::Id index, vtkm::cont::ArrayHandle<vtkm::Id>& ids) const
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::GetIndices(vtkm::Id cellId, vtkm::cont::ArrayHandle<vtkm::Id>& ids) const
{
this->Data->VisitCellsWithPoints.BuildIndexOffsets(vtkm::cont::DeviceAdapterTagAny{});
vtkm::IdComponent numIndices = this->GetNumberOfPointsInCell(index);
const auto offPortal = this->Data->CellPointIds.Offsets.GetPortalConstControl();
const vtkm::Id start = offPortal.Get(cellId);
const vtkm::Id end = offPortal.Get(cellId + 1);
const vtkm::IdComponent numIndices = static_cast<vtkm::IdComponent>(end - start);
ids.Allocate(numIndices);
vtkm::Id start = this->Data->VisitCellsWithPoints.IndexOffsets.GetPortalConstControl().Get(index);
vtkm::cont::ArrayHandle<vtkm::Id>::PortalControl idPortal = ids.GetPortalControl();
auto PtCellPortal = this->Data->VisitCellsWithPoints.Connectivity.GetPortalConstControl();
auto connPortal = this->Data->CellPointIds.Connectivity.GetPortalConstControl();
for (vtkm::IdComponent i = 0; i < numIndices && i < numIndices; i++)
auto outIdPortal = ids.GetPortalControl();
for (vtkm::IdComponent i = 0; i < numIndices; i++)
{
idPortal.Set(i, PtCellPortal.Get(start + i));
outIdPortal.Set(i, connPortal.Get(start + i));
}
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::PrepareToAddCells(vtkm::Id numCells,
vtkm::Id connectivityMaxLen)
namespace internal
{
this->Data->VisitCellsWithPoints.Shapes.Allocate(numCells);
this->Data->VisitCellsWithPoints.NumIndices.Allocate(numCells);
this->Data->VisitCellsWithPoints.Connectivity.Allocate(connectivityMaxLen);
this->Data->VisitCellsWithPoints.IndexOffsets.Allocate(numCells);
// Sets the first value of the array to zero if the handle is writable,
// otherwise do nothing:
template <typename ArrayType>
typename std::enable_if<vtkm::cont::internal::IsWritableArrayHandle<ArrayType>::value>::type
SetFirstToZeroIfWritable(ArrayType&& array)
{
using ValueType = typename std::decay<ArrayType>::type::ValueType;
using Traits = vtkm::TypeTraits<ValueType>;
array.GetPortalControl().Set(0, Traits::ZeroInitialization());
}
template <typename ArrayType>
typename std::enable_if<!vtkm::cont::internal::IsWritableArrayHandle<ArrayType>::value>::type
SetFirstToZeroIfWritable(ArrayType&&)
{ /* no-op */ }
} // end namespace internal
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::PrepareToAddCells(vtkm::Id numCells,
vtkm::Id connectivityMaxLen)
{
this->Data->CellPointIds.Shapes.Allocate(numCells);
this->Data->CellPointIds.Connectivity.Allocate(connectivityMaxLen);
this->Data->CellPointIds.Offsets.Allocate(numCells + 1);
internal::SetFirstToZeroIfWritable(this->Data->CellPointIds.Offsets);
this->Data->NumberOfCellsAdded = 0;
this->Data->ConnectivityAdded = 0;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename IdVecType>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
AddCell(vtkm::UInt8 cellType, vtkm::IdComponent numVertices, const IdVecType& ids)
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::AddCell(vtkm::UInt8 cellType,
vtkm::IdComponent numVertices,
const IdVecType& ids)
{
using Traits = vtkm::VecTraits<IdVecType>;
VTKM_STATIC_ASSERT_MSG((std::is_same<typename Traits::ComponentType, vtkm::Id>::value),
@ -313,48 +278,45 @@ CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, O
if (Traits::GetNumberOfComponents(ids) < numVertices)
{
throw vtkm::cont::ErrorBadValue("Not enough indices given to CellSetSingleType::AddCell.");
throw vtkm::cont::ErrorBadValue("Not enough indices given to CellSetExplicit::AddCell.");
}
if (this->Data->NumberOfCellsAdded >= this->Data->VisitCellsWithPoints.Shapes.GetNumberOfValues())
if (this->Data->NumberOfCellsAdded >= this->Data->CellPointIds.Shapes.GetNumberOfValues())
{
throw vtkm::cont::ErrorBadValue("Added more cells then expected.");
}
if (this->Data->ConnectivityAdded + numVertices >
this->Data->VisitCellsWithPoints.Connectivity.GetNumberOfValues())
this->Data->CellPointIds.Connectivity.GetNumberOfValues())
{
throw vtkm::cont::ErrorBadValue(
"Connectivity increased passed estimated maximum connectivity.");
"Connectivity increased past estimated maximum connectivity.");
}
this->Data->VisitCellsWithPoints.Shapes.GetPortalControl().Set(this->Data->NumberOfCellsAdded,
cellType);
this->Data->VisitCellsWithPoints.NumIndices.GetPortalControl().Set(this->Data->NumberOfCellsAdded,
numVertices);
auto shapes = this->Data->CellPointIds.Shapes.GetPortalControl();
auto conn = this->Data->CellPointIds.Connectivity.GetPortalControl();
auto offsets = this->Data->CellPointIds.Offsets.GetPortalControl();
shapes.Set(this->Data->NumberOfCellsAdded, cellType);
for (vtkm::IdComponent iVec = 0; iVec < numVertices; ++iVec)
{
this->Data->VisitCellsWithPoints.Connectivity.GetPortalControl().Set(
this->Data->ConnectivityAdded + iVec, Traits::GetComponent(ids, iVec));
conn.Set(this->Data->ConnectivityAdded + iVec,
Traits::GetComponent(ids, iVec));
}
this->Data->VisitCellsWithPoints.IndexOffsets.GetPortalControl().Set(
this->Data->NumberOfCellsAdded, this->Data->ConnectivityAdded);
this->Data->NumberOfCellsAdded++;
this->Data->ConnectivityAdded += numVertices;
// Set the end offset for the added cell:
offsets.Set(this->Data->NumberOfCellsAdded, this->Data->ConnectivityAdded);
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::CompleteAddingCells(vtkm::Id numPoints)
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::CompleteAddingCells(vtkm::Id numPoints)
{
this->Data->NumberOfPoints = numPoints;
this->Data->VisitCellsWithPoints.Connectivity.Shrink(this->Data->ConnectivityAdded);
this->Data->VisitCellsWithPoints.ElementsValid = true;
this->Data->VisitCellsWithPoints.IndexOffsetsValid = true;
this->Data->CellPointIds.Connectivity.Shrink(this->Data->ConnectivityAdded);
this->Data->CellPointIds.ElementsValid = true;
if (this->Data->NumberOfCellsAdded != this->GetNumberOfCells())
{
@ -367,159 +329,132 @@ VTKM_CONT void CellSetExplicit<ShapeStorageTag,
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
Fill(vtkm::Id numPoints,
const vtkm::cont::ArrayHandle<vtkm::UInt8, ShapeStorageTag>& cellTypes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent, NumIndicesStorageTag>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityStorageTag>& connectivity,
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& offsets)
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::Fill(vtkm::Id numPoints,
const vtkm::cont::ArrayHandle<vtkm::UInt8, SST>& shapes,
const vtkm::cont::ArrayHandle<vtkm::Id, CST>& connectivity,
const vtkm::cont::ArrayHandle<vtkm::Id, OST>& offsets)
{
// Validate inputs:
// Even for an empty cellset, offsets must contain a single 0:
VTKM_ASSERT(offsets.GetNumberOfValues() > 0);
// Must be [numCells + 1] offsets and [numCells] shapes
VTKM_ASSERT(offsets.GetNumberOfValues() == shapes.GetNumberOfValues() + 1);
// The last offset must be the size of the connectivity array.
VTKM_ASSERT(vtkm::cont::ArrayGetValue(offsets.GetNumberOfValues() - 1,
offsets) ==
connectivity.GetNumberOfValues());
this->Data->NumberOfPoints = numPoints;
this->Data->VisitCellsWithPoints.Shapes = cellTypes;
this->Data->VisitCellsWithPoints.NumIndices = numIndices;
this->Data->VisitCellsWithPoints.Connectivity = connectivity;
this->Data->CellPointIds.Shapes = shapes;
this->Data->CellPointIds.Connectivity = connectivity;
this->Data->CellPointIds.Offsets = offsets;
this->Data->VisitCellsWithPoints.ElementsValid = true;
if (offsets.GetNumberOfValues() == cellTypes.GetNumberOfValues())
{
this->Data->VisitCellsWithPoints.IndexOffsets = offsets;
this->Data->VisitCellsWithPoints.IndexOffsetsValid = true;
}
else
{
this->Data->VisitCellsWithPoints.IndexOffsetsValid = false;
if (offsets.GetNumberOfValues() != 0)
{
throw vtkm::cont::ErrorBadValue("Explicit cell offsets array unexpected size. "
"Use an empty array to automatically generate.");
}
}
this->Data->CellPointIds.ElementsValid = true;
this->ResetConnectivity(TopologyElementTagPoint{}, TopologyElementTagCell{});
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename Device, typename VisitTopology, typename IncidentTopology>
auto CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::PrepareForInput(Device,
VisitTopology,
IncidentTopology) const ->
typename ExecutionTypes<Device, VisitTopology, IncidentTopology>::ExecObjectType
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>
::PrepareForInput(Device, VisitTopology, IncidentTopology) const
-> typename ExecutionTypes<Device,
VisitTopology,
IncidentTopology>::ExecObjectType
{
this->BuildConnectivity(Device{}, VisitTopology(), IncidentTopology());
this->BuildConnectivity(Device{}, VisitTopology{}, IncidentTopology{});
const auto& connectivity = this->GetConnectivity(VisitTopology(), IncidentTopology());
const auto& connectivity = this->GetConnectivity(VisitTopology{},
IncidentTopology{});
VTKM_ASSERT(connectivity.ElementsValid);
using ExecObjType =
typename ExecutionTypes<Device, VisitTopology, IncidentTopology>::ExecObjectType;
return ExecObjType(connectivity.Shapes.PrepareForInput(Device()),
connectivity.NumIndices.PrepareForInput(Device()),
connectivity.Connectivity.PrepareForInput(Device()),
connectivity.IndexOffsets.PrepareForInput(Device()));
using ExecObjType = typename ExecutionTypes<Device,
VisitTopology,
IncidentTopology>::ExecObjectType;
return ExecObjType(connectivity.Shapes.PrepareForInput(Device{}),
connectivity.Connectivity.PrepareForInput(Device{}),
connectivity.Offsets.PrepareForInput(Device{}));
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT auto CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetShapesArray(VisitTopology,
IncidentTopology) const -> const
typename ConnectivityChooser<VisitTopology, IncidentTopology>::ShapeArrayType&
VTKM_CONT auto CellSetExplicit<SST, CST, OST>
::GetShapesArray(VisitTopology, IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::ShapesArrayType&
{
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology(), IncidentTopology());
return this->GetConnectivity(VisitTopology(), IncidentTopology()).Shapes;
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{},
VisitTopology{},
IncidentTopology{});
return this->GetConnectivity(VisitTopology{}, IncidentTopology{}).Shapes;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT auto CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetNumIndicesArray(VisitTopology,
IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology, IncidentTopology>::NumIndicesArrayType&
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>
::GetConnectivityArray(VisitTopology, IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::ConnectivityArrayType&
{
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology(), IncidentTopology());
return this->GetConnectivity(VisitTopology(), IncidentTopology()).NumIndices;
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{},
VisitTopology{},
IncidentTopology{});
return this->GetConnectivity(VisitTopology{},
IncidentTopology{}).Connectivity;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT auto CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetConnectivityArray(VisitTopology,
IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology, IncidentTopology>::ConnectivityArrayType&
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>
::GetOffsetsArray(VisitTopology, IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology,
IncidentTopology>::OffsetsArrayType&
{
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology(), IncidentTopology());
return this->GetConnectivity(VisitTopology(), IncidentTopology()).Connectivity;
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{},
VisitTopology{},
IncidentTopology{});
return this->GetConnectivity(VisitTopology{},
IncidentTopology{}).Offsets;
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
template <typename SST, typename CST, typename OST>
template <typename VisitTopology, typename IncidentTopology>
VTKM_CONT auto CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::GetIndexOffsetArray(VisitTopology,
IncidentTopology) const
-> const typename ConnectivityChooser<VisitTopology, IncidentTopology>::IndexOffsetArrayType&
VTKM_CONT
auto CellSetExplicit<SST, CST, OST>
::GetNumIndicesArray(VisitTopology visited, IncidentTopology incident) const
-> typename ConnectivityChooser<VisitTopology,
IncidentTopology>::NumIndicesArrayType
{
this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology(), IncidentTopology());
return this->GetConnectivity(VisitTopology(), IncidentTopology()).IndexOffsets;
auto offsets = this->GetOffsetsArray(visited, incident);
const vtkm::Id numVals = offsets.GetNumberOfValues() - 1;
return vtkm::cont::make_ArrayHandleDecorator(numVals,
detail::NumIndicesDecorator{},
std::move(offsets));
}
//----------------------------------------------------------------------------
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
std::shared_ptr<CellSet> CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::NewInstance() const
template <typename SST, typename CST, typename OST>
VTKM_CONT
std::shared_ptr<CellSet> CellSetExplicit<SST, CST, OST>::NewInstance() const
{
return std::make_shared<CellSetExplicit>();
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
void CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>::DeepCopy(const CellSet* src)
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>::DeepCopy(const CellSet* src)
{
const auto* other = dynamic_cast<const CellSetExplicit*>(src);
if (!other)
@ -527,14 +462,18 @@ void CellSetExplicit<ShapeStorageTag,
throw vtkm::cont::ErrorBadType("CellSetExplicit::DeepCopy types don't match");
}
// TODO: implement actual deep-copy of the arrays
auto ct = vtkm::TopologyElementTagCell{};
auto pt = vtkm::TopologyElementTagPoint{};
this->Fill(other->GetNumberOfPoints(),
other->GetShapesArray(ct, pt),
other->GetNumIndicesArray(ct, pt),
other->GetConnectivityArray(ct, pt),
other->GetIndexOffsetArray(ct, pt));
ShapesArrayType shapes;
ConnectivityArrayType conn;
OffsetsArrayType offsets;
const auto ct = vtkm::TopologyElementTagCell{};
const auto pt = vtkm::TopologyElementTagPoint{};
vtkm::cont::ArrayCopy(other->GetShapesArray(ct, pt), shapes);
vtkm::cont::ArrayCopy(other->GetConnectivityArray(ct, pt), conn);
vtkm::cont::ArrayCopy(other->GetOffsetsArray(ct, pt), offsets);
this->Fill(other->GetNumberOfPoints(), shapes, conn, offsets);
}
//----------------------------------------------------------------------------
@ -542,33 +481,14 @@ void CellSetExplicit<ShapeStorageTag,
namespace detail
{
template <typename VisitCellsWithPointsConnectivity>
struct BuildVisitCellsWithPointsConnectivityFunctor
template <typename CellPointIdsT, typename PointCellIdsT>
struct BuildPointCellIdsFunctor
{
explicit BuildVisitCellsWithPointsConnectivityFunctor(VisitCellsWithPointsConnectivity& obj)
: VisitCellsWithPoints(&obj)
{
}
template <typename Device>
bool operator()(Device) const
{
this->VisitCellsWithPoints->BuildIndexOffsets(Device());
return true;
}
VisitCellsWithPointsConnectivity* VisitCellsWithPoints;
};
template <typename VisitCellsWithPointsConnectivity, typename VisitPointsWithCellsConnectivity>
struct BuildVisitPointsWithCellsConnectivityFunctor
{
BuildVisitPointsWithCellsConnectivityFunctor(
VisitCellsWithPointsConnectivity& visitCellsWithPoints,
VisitPointsWithCellsConnectivity& visitPointsWithCells,
vtkm::Id numberOfPoints)
: VisitCellsWithPoints(&visitCellsWithPoints)
, VisitPointsWithCells(&visitPointsWithCells)
BuildPointCellIdsFunctor(CellPointIdsT &cellPointIds,
PointCellIdsT &pointCellIds,
vtkm::Id numberOfPoints)
: CellPointIds(cellPointIds)
, PointCellIds(pointCellIds)
, NumberOfPoints(numberOfPoints)
{
}
@ -576,81 +496,57 @@ struct BuildVisitPointsWithCellsConnectivityFunctor
template <typename Device>
bool operator()(Device) const
{
this->VisitCellsWithPoints->BuildIndexOffsets(Device());
internal::ComputeVisitPointsWithCellsConnectivity(
*this->VisitPointsWithCells, *this->VisitCellsWithPoints, this->NumberOfPoints, Device());
this->VisitPointsWithCells->BuildIndexOffsets(Device());
internal::ComputeRConnTable(this->PointCellIds,
this->CellPointIds,
this->NumberOfPoints,
Device{});
return true;
}
VisitCellsWithPointsConnectivity* VisitCellsWithPoints;
VisitPointsWithCellsConnectivity* VisitPointsWithCells;
CellPointIdsT &CellPointIds;
PointCellIdsT &PointCellIds;
vtkm::Id NumberOfPoints;
};
} // detail
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
BuildConnectivity(vtkm::cont::DeviceAdapterId device,
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::BuildConnectivity(vtkm::cont::DeviceAdapterId,
vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint) const
{
using VisitCellsWithPointsConnectivity =
typename ConnectivityChooser<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint>::ConnectivityType;
VTKM_ASSERT(this->Data->VisitCellsWithPoints.ElementsValid);
if (!this->Data->VisitCellsWithPoints.IndexOffsetsValid)
{
auto self = const_cast<Thisclass*>(this);
auto functor =
detail::BuildVisitCellsWithPointsConnectivityFunctor<VisitCellsWithPointsConnectivity>(
self->Data->VisitCellsWithPoints);
if (!vtkm::cont::TryExecuteOnDevice(device, functor))
{
throw vtkm::cont::ErrorExecution("Failed to run BuildConnectivity.");
}
}
VTKM_ASSERT(this->Data->CellPointIds.ElementsValid);
// no-op
}
template <typename ShapeStorageTag,
typename NumIndicesStorageTag,
typename ConnectivityStorageTag,
typename OffsetsStorageTag>
VTKM_CONT void
CellSetExplicit<ShapeStorageTag, NumIndicesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>::
BuildConnectivity(vtkm::cont::DeviceAdapterId device,
template <typename SST, typename CST, typename OST>
VTKM_CONT
void CellSetExplicit<SST, CST, OST>
::BuildConnectivity(vtkm::cont::DeviceAdapterId device,
vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell) const
{
using VisitCellsWithPointsConnectivity =
typename ConnectivityChooser<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint>::ConnectivityType;
using VisitPointsWithCellsConnectivity =
typename ConnectivityChooser<vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell>::ConnectivityType;
if (!this->Data->VisitPointsWithCells.ElementsValid ||
!this->Data->VisitPointsWithCells.IndexOffsetsValid)
if (!this->Data->PointCellIds.ElementsValid)
{
auto self = const_cast<Thisclass*>(this);
auto functor =
detail::BuildVisitPointsWithCellsConnectivityFunctor<VisitCellsWithPointsConnectivity,
VisitPointsWithCellsConnectivity>(
self->Data->VisitCellsWithPoints,
self->Data->VisitPointsWithCells,
this->Data->NumberOfPoints);
using Func = detail::BuildPointCellIdsFunctor<CellPointIdsType, PointCellIdsType>;
auto functor = Func(self->Data->CellPointIds,
self->Data->PointCellIds,
self->Data->NumberOfPoints);
if (!vtkm::cont::TryExecuteOnDevice(device, functor))
{
throw vtkm::cont::ErrorExecution("Failed to run BuildConnectivity.");
throw vtkm::cont::ErrorExecution("Failed to run CellSetExplicit reverse "
"connectivity builder.");
}
}
}
}
} // vtkm::cont
// clang-format on
#endif

@ -15,7 +15,6 @@ namespace
struct ComputeReverseMapping : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn cellIndex, WholeArrayOut cellIds);
using ExecutionSignature = void(_1, _2);
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename PortalType>

@ -42,15 +42,12 @@ struct VTKM_ALWAYS_EXPORT CellSetListTagStructured3D
};
template <typename ShapeStorageTag = VTKM_DEFAULT_SHAPE_STORAGE_TAG,
typename NumIndicesStorageTag = VTKM_DEFAULT_NUM_INDICES_STORAGE_TAG,
template <typename ShapesStorageTag = VTKM_DEFAULT_SHAPES_STORAGE_TAG,
typename ConnectivityStorageTag = VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
typename OffsetsStorageTag = VTKM_DEFAULT_OFFSETS_STORAGE_TAG>
struct VTKM_ALWAYS_EXPORT CellSetListTagExplicit
: vtkm::ListTagBase<vtkm::cont::CellSetExplicit<ShapeStorageTag,
NumIndicesStorageTag,
ConnectivityStorageTag,
OffsetsStorageTag>>
: vtkm::ListTagBase<
vtkm::cont::CellSetExplicit<ShapesStorageTag, ConnectivityStorageTag, OffsetsStorageTag>>
{
};

@ -12,13 +12,15 @@
#include <vtkm/CellShape.h>
#include <vtkm/CellTraits.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/CellSet.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/internal/ConnectivityExplicitInternals.h>
#include <vtkm/internal/ConnectivityStructuredInternals.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/exec/ConnectivityPermuted.h>
@ -35,7 +37,12 @@ namespace cont
namespace internal
{
class CellSetPermutationVisitCellsWithPointsHelpers
// To generate the reverse connectivity table with the
// ReverseConnectivityBuilder, we need a compact connectivity array that
// contains only the cell definitions from the permuted dataset, and an offsets
// array. These helpers are used to generate these arrays so that they can be
// converted in the reverse conn table.
class RConnTableHelpers
{
public:
struct WriteNumIndices : public vtkm::worklet::WorkletVisitCellsWithPoints
@ -70,102 +77,137 @@ public:
public:
template <typename CellSetPermutationType, typename Device>
static vtkm::cont::ArrayHandle<vtkm::IdComponent> GetNumIndicesArray(
static VTKM_CONT vtkm::cont::ArrayHandle<vtkm::IdComponent> GetNumIndicesArray(
const CellSetPermutationType& cs,
Device)
{
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::worklet::DispatcherMapTopology<WriteNumIndices> dispatcher;
dispatcher.SetDevice(Device());
dispatcher.Invoke(cs, numIndices);
vtkm::cont::Invoker{ Device{} }(WriteNumIndices{}, cs, numIndices);
return numIndices;
}
template <typename NumIndicesStorageType, typename Device>
static vtkm::cont::ArrayHandle<vtkm::Id> GetIndexOffsetsArray(
static VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> GetOffsetsArray(
const vtkm::cont::ArrayHandle<vtkm::IdComponent, NumIndicesStorageType>& numIndices,
vtkm::Id& connectivityLength,
vtkm::Id& connectivityLength /* outparam */,
Device)
{
return vtkm::cont::ConvertNumComponentsToOffsets(numIndices, connectivityLength);
return vtkm::cont::ConvertNumIndicesToOffsets(numIndices, connectivityLength);
}
template <typename CellSetPermutationType, typename IndexOffsetsStorageType, typename Device>
template <typename CellSetPermutationType, typename OffsetsStorageType, typename Device>
static vtkm::cont::ArrayHandle<vtkm::Id> GetConnectivityArray(
const CellSetPermutationType& cs,
const vtkm::cont::ArrayHandle<vtkm::Id, IndexOffsetsStorageType>& indexOffsets,
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageType>& offsets,
vtkm::Id connectivityLength,
Device)
{
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
connectivity.Allocate(connectivityLength);
vtkm::worklet::DispatcherMapTopology<WriteConnectivity> dispatcher;
dispatcher.SetDevice(Device());
dispatcher.Invoke(cs, vtkm::cont::make_ArrayHandleGroupVecVariable(connectivity, indexOffsets));
const auto offsetsTrim =
vtkm::cont::make_ArrayHandleView(offsets, 0, offsets.GetNumberOfValues() - 1);
auto connWrap = vtkm::cont::make_ArrayHandleGroupVecVariable(connectivity, offsetsTrim);
vtkm::cont::Invoker{ Device{} }(WriteConnectivity{}, cs, connWrap);
return connectivity;
}
};
// This holds the temporary input arrays for the ReverseConnectivityBuilder
// algorithm.
template <typename ConnectivityStorageTag = VTKM_DEFAULT_STORAGE_TAG,
typename OffsetsStorageTag = VTKM_DEFAULT_STORAGE_TAG,
typename NumIndicesStorageTag = VTKM_DEFAULT_STORAGE_TAG>
struct RConnBuilderInputData
{
using ConnectivityArrayType = vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityStorageTag>;
using OffsetsArrayType = vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>;
using NumIndicesArrayType = vtkm::cont::ArrayHandle<vtkm::IdComponent, NumIndicesStorageTag>;
ConnectivityArrayType Connectivity;
OffsetsArrayType Offsets; // Includes the past-the-end offset.
NumIndicesArrayType NumIndices;
};
// default for CellSetPermutations of any cell type
template <typename CellSetPermutationType>
class CellSetPermutationVisitCellsWithPoints
class RConnBuilderInput
{
public:
using ConnectivityArrays = vtkm::cont::internal::ConnectivityExplicitInternals<>;
using ConnectivityArrays = vtkm::cont::internal::RConnBuilderInputData<>;
template <typename Device>
static ConnectivityArrays Get(const CellSetPermutationType& cellset, Device)
{
using Helper = RConnTableHelpers;
ConnectivityArrays conn;
vtkm::Id connectivityLength = 0;
conn.NumIndices =
CellSetPermutationVisitCellsWithPointsHelpers::GetNumIndicesArray(cellset, Device{});
conn.IndexOffsets = CellSetPermutationVisitCellsWithPointsHelpers::GetIndexOffsetsArray(
conn.NumIndices, connectivityLength, Device{});
conn.Connectivity = CellSetPermutationVisitCellsWithPointsHelpers::GetConnectivityArray(
cellset, conn.IndexOffsets, connectivityLength, Device{});
conn.NumIndices = Helper::GetNumIndicesArray(cellset, Device{});
conn.Offsets = Helper::GetOffsetsArray(conn.NumIndices, connectivityLength, Device{});
conn.Connectivity =
Helper::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, Device{});
return conn;
}
};
// Specialization for CellSetExplicit/CellSetSingleType
template <typename S1, typename S2, typename S3, typename S4, typename PermutationArrayHandleType>
class CellSetPermutationVisitCellsWithPoints<
CellSetPermutation<CellSetExplicit<S1, S2, S3, S4>, PermutationArrayHandleType>>
template <typename InShapesST,
typename InConnST,
typename InOffsetsST,
typename PermutationArrayHandleType>
class RConnBuilderInput<CellSetPermutation<CellSetExplicit<InShapesST, InConnST, InOffsetsST>,
PermutationArrayHandleType>>
{
private:
using CellSetPermutationType =
CellSetPermutation<CellSetExplicit<S1, S2, S3, S4>, PermutationArrayHandleType>;
using BaseCellSetType = CellSetExplicit<InShapesST, InConnST, InOffsetsST>;
using CellSetPermutationType = CellSetPermutation<BaseCellSetType, PermutationArrayHandleType>;
using InShapesArrayType = typename BaseCellSetType::ShapesArrayType;
using InNumIndicesArrayType = typename BaseCellSetType::NumIndicesArrayType;
using ShapesStorageTag = StorageTagPermutation<PermutationArrayHandleType, InShapesArrayType>;
using ConnectivityStorageTag = vtkm::cont::ArrayHandle<vtkm::Id>::StorageTag;
using OffsetsStorageTag = vtkm::cont::ArrayHandle<vtkm::Id>::StorageTag;
using NumIndicesStorageTag =
StorageTagPermutation<PermutationArrayHandleType, InNumIndicesArrayType>;
using NumIndicesArrayType =
vtkm::cont::ArrayHandlePermutation<PermutationArrayHandleType,
vtkm::cont::ArrayHandle<vtkm::IdComponent, S2>>;
public:
using ConnectivityArrays = vtkm::cont::internal::ConnectivityExplicitInternals<
VTKM_DEFAULT_STORAGE_TAG, // shapes array is not used
typename NumIndicesArrayType::StorageTag>;
using ConnectivityArrays = vtkm::cont::internal::RConnBuilderInputData<ConnectivityStorageTag,
OffsetsStorageTag,
NumIndicesStorageTag>;
template <typename Device>
static ConnectivityArrays Get(const CellSetPermutationType& cellset, Device)
{
ConnectivityArrays conn;
vtkm::Id connectivityLength = 0;
using Helper = RConnTableHelpers;
conn.NumIndices =
NumIndicesArrayType(cellset.GetValidCellIds(),
cellset.GetFullCellSet().GetNumIndicesArray(
vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()));
conn.IndexOffsets = CellSetPermutationVisitCellsWithPointsHelpers::GetIndexOffsetsArray(
conn.NumIndices, connectivityLength, Device{});
conn.Connectivity = CellSetPermutationVisitCellsWithPointsHelpers::GetConnectivityArray(
cellset, conn.IndexOffsets, connectivityLength, Device{});
static constexpr vtkm::TopologyElementTagCell cell{};
static constexpr vtkm::TopologyElementTagPoint point{};
auto fullCellSet = cellset.GetFullCellSet();
vtkm::Id connectivityLength = 0;
ConnectivityArrays conn;
fullCellSet.GetOffsetsArray(cell, point);
// We can use the implicitly generated NumIndices array to save a bit of
// memory:
conn.NumIndices = vtkm::cont::make_ArrayHandlePermutation(
cellset.GetValidCellIds(), fullCellSet.GetNumIndicesArray(cell, point));
// Need to generate the offsets from scratch so that they're ordered for the
// lower-bounds binary searches in ReverseConnectivityBuilder.
conn.Offsets = Helper::GetOffsetsArray(conn.NumIndices, connectivityLength, Device{});
// Need to create a copy of this containing *only* the permuted cell defs,
// in order, since the ReverseConnectivityBuilder will process every entry
// in the connectivity array and we don't want the removed cells to be
// included.
conn.Connectivity =
Helper::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, Device{});
return conn;
}
@ -173,7 +215,7 @@ public:
// Specialization for CellSetStructured
template <vtkm::IdComponent DIMENSION, typename PermutationArrayHandleType>
class CellSetPermutationVisitCellsWithPoints<
class RConnBuilderInput<
CellSetPermutation<CellSetStructured<DIMENSION>, PermutationArrayHandleType>>
{
private:
@ -181,11 +223,10 @@ private:
CellSetPermutation<CellSetStructured<DIMENSION>, PermutationArrayHandleType>;
public:
using ConnectivityArrays = vtkm::cont::internal::ConnectivityExplicitInternals<
VTKM_DEFAULT_STORAGE_TAG, // shapes array is not used
typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag,
using ConnectivityArrays = vtkm::cont::internal::RConnBuilderInputData<
VTKM_DEFAULT_STORAGE_TAG,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>;
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag,
typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag>;
template <typename Device>
static ConnectivityArrays Get(const CellSetPermutationType& cellset, Device)
@ -197,9 +238,9 @@ public:
ConnectivityArrays conn;
conn.NumIndices = make_ArrayHandleConstant(numPointsInCell, numberOfCells);
conn.IndexOffsets = ArrayHandleCounting<vtkm::Id>(0, numPointsInCell, numberOfCells);
conn.Connectivity = CellSetPermutationVisitCellsWithPointsHelpers::GetConnectivityArray(
cellset, conn.IndexOffsets, connectivityLength, Device{});
conn.Offsets = ArrayHandleCounting<vtkm::Id>(0, numPointsInCell, numberOfCells + 1);
conn.Connectivity =
RConnTableHelpers::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, Device{});
return conn;
}
@ -312,11 +353,11 @@ public:
const auto* other = dynamic_cast<const CellSetPermutation*>(src);
if (!other)
{
throw vtkm::cont::ErrorBadType("CellSetPermutaion::DeepCopy types don't match");
throw vtkm::cont::ErrorBadType("CellSetPermutation::DeepCopy types don't match");
}
this->FullCellSet.DeepCopy(&(other->GetFullCellSet()));
this->ValidCellIds = other->GetValidCellIds();
vtkm::cont::ArrayCopy(other->GetValidCellIds(), this->ValidCellIds);
}
//This is the way you can fill the memory from another system without copying
@ -361,17 +402,16 @@ public:
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
using ConnectiviyPortalType =
using ConnectivityPortalType =
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<Device>::PortalConst;
using NumIndicesPortalType = typename vtkm::cont::ArrayHandle<
vtkm::IdComponent>::template ExecutionTypes<Device>::PortalConst;
using IndexOffsetPortalType =
using OffsetPortalType =
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<Device>::PortalConst;
using ExecObjectType =
vtkm::exec::ConnectivityPermutedVisitPointsWithCells<ConnectiviyPortalType,
NumIndicesPortalType,
IndexOffsetPortalType>;
vtkm::exec::ConnectivityPermutedVisitPointsWithCells<ConnectivityPortalType,
OffsetPortalType>;
};
template <typename Device>
@ -397,19 +437,16 @@ public:
{
if (!this->VisitPointsWithCells.ElementsValid)
{
auto pointToCell =
internal::CellSetPermutationVisitCellsWithPoints<CellSetPermutation>::Get(*this, device);
internal::ComputeVisitPointsWithCellsConnectivity(
this->VisitPointsWithCells, pointToCell, this->GetNumberOfPoints(), device);
this->VisitPointsWithCells.BuildIndexOffsets(device);
auto connTable = internal::RConnBuilderInput<CellSetPermutation>::Get(*this, device);
internal::ComputeRConnTable(
this->VisitPointsWithCells, connTable, this->GetNumberOfPoints(), device);
}
using ConnectivityType = typename ExecutionTypes<Device,
vtkm::TopologyElementTagPoint,
vtkm::TopologyElementTagCell>::ExecObjectType;
return ConnectivityType(this->VisitPointsWithCells.Connectivity.PrepareForInput(device),
this->VisitPointsWithCells.NumIndices.PrepareForInput(device),
this->VisitPointsWithCells.IndexOffsets.PrepareForInput(device));
this->VisitPointsWithCells.Offsets.PrepareForInput(device));
}
VTKM_CONT

@ -30,19 +30,16 @@ namespace cont
template <typename ConnectivityStorageTag = VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG>
class VTKM_ALWAYS_EXPORT CellSetSingleType
: public vtkm::cont::CellSetExplicit<
typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag, //ShapeStorageTag
typename vtkm::cont::ArrayHandleConstant<
vtkm::IdComponent>::StorageTag, //NumIndicesStorageTag
typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag, //ShapesStorageTag
ConnectivityStorageTag,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag //IndexOffsetStorageTag
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag //OffsetsStorageTag
>
{
using Thisclass = vtkm::cont::CellSetSingleType<ConnectivityStorageTag>;
using Superclass = vtkm::cont::CellSetExplicit<
typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
typename vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag,
ConnectivityStorageTag,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>;
using Superclass =
vtkm::cont::CellSetExplicit<typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
ConnectivityStorageTag,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>;
public:
VTKM_CONT
@ -98,7 +95,7 @@ public:
{
this->CellShapeAsId = vtkm::CELL_SHAPE_EMPTY;
this->Data->VisitCellsWithPoints.Connectivity.Allocate(connectivityMaxLen);
this->Data->CellPointIds.Connectivity.Allocate(connectivityMaxLen);
this->Data->NumberOfCellsAdded = 0;
this->Data->ConnectivityAdded = 0;
@ -119,10 +116,10 @@ public:
}
if (this->Data->ConnectivityAdded + numVertices >
this->Data->VisitCellsWithPoints.Connectivity.GetNumberOfValues())
this->Data->CellPointIds.Connectivity.GetNumberOfValues())
{
throw vtkm::cont::ErrorBadValue(
"Connectivity increased passed estimated maximum connectivity.");
"Connectivity increased past estimated maximum connectivity.");
}
if (this->CellShapeAsId == vtkm::CELL_SHAPE_EMPTY)
@ -147,10 +144,10 @@ public:
"Inconsistent number of points in cells for CellSetSingleType.");
}
}
auto conn = this->Data->CellPointIds.Connectivity.GetPortalControl();
for (vtkm::IdComponent iVert = 0; iVert < numVertices; ++iVert)
{
this->Data->VisitCellsWithPoints.Connectivity.GetPortalControl().Set(
this->Data->ConnectivityAdded + iVert, Traits::GetComponent(ids, iVert));
conn.Set(this->Data->ConnectivityAdded + iVert, Traits::GetComponent(ids, iVert));
}
this->Data->NumberOfCellsAdded++;
this->Data->ConnectivityAdded += numVertices;
@ -161,19 +158,16 @@ public:
void CompleteAddingCells(vtkm::Id numPoints)
{
this->Data->NumberOfPoints = numPoints;
this->VisitCellsWithPoints.Connectivity.Shrink(this->ConnectivityAdded);
this->CellPointIds.Connectivity.Shrink(this->ConnectivityAdded);
vtkm::Id numCells = this->NumberOfCellsAdded;
this->VisitCellsWithPoints.Shapes =
this->CellPointIds.Shapes =
vtkm::cont::make_ArrayHandleConstant(this->GetCellShape(0), numCells);
this->VisitCellsWithPoints.NumIndices =
vtkm::cont::make_ArrayHandleConstant(this->NumberOfPointsPerCell, numCells);
this->VisitCellsWithPoints.IndexOffsets = vtkm::cont::make_ArrayHandleCounting(
this->CellPointIds.IndexOffsets = vtkm::cont::make_ArrayHandleCounting(
vtkm::Id(0), static_cast<vtkm::Id>(this->NumberOfPointsPerCell), numCells);
this->VisitCellsWithPoints.ElementsValid = true;
this->VisitCellsWithPoints.IndexOffsetsValid = true;
this->CellPointIds.ElementsValid = true;
if (this->ExpectedNumberOfCellsAdded != this->GetNumberOfCells())
{
@ -195,18 +189,18 @@ public:
this->Data->NumberOfPoints = numPoints;
this->CellShapeAsId = shapeId;
this->CheckNumberOfPointsPerCell(numberOfPointsPerCell);
const vtkm::Id numCells = connectivity.GetNumberOfValues() / numberOfPointsPerCell;
VTKM_ASSERT((connectivity.GetNumberOfValues() % numberOfPointsPerCell) == 0);
this->Data->VisitCellsWithPoints.Shapes =
vtkm::cont::make_ArrayHandleConstant(shapeId, numCells);
this->Data->VisitCellsWithPoints.NumIndices =
vtkm::cont::make_ArrayHandleConstant(numberOfPointsPerCell, numCells);
this->Data->VisitCellsWithPoints.IndexOffsets = vtkm::cont::make_ArrayHandleCounting(
vtkm::Id(0), static_cast<vtkm::Id>(numberOfPointsPerCell), numCells);
this->Data->VisitCellsWithPoints.Connectivity = connectivity;
this->Data->VisitCellsWithPoints.ElementsValid = true;
this->Data->VisitCellsWithPoints.IndexOffsetsValid = true;
this->Data->CellPointIds.Shapes = vtkm::cont::make_ArrayHandleConstant(shapeId, numCells);
this->Data->CellPointIds.Offsets = vtkm::cont::make_ArrayHandleCounting(
vtkm::Id(0), static_cast<vtkm::Id>(numberOfPointsPerCell), numCells + 1);
this->Data->CellPointIds.Connectivity = connectivity;
this->Data->CellPointIds.ElementsValid = true;
this->ResetConnectivity(TopologyElementTagPoint{}, TopologyElementTagCell{});
}
@ -242,11 +236,11 @@ public:
virtual void PrintSummary(std::ostream& out) const override
{
out << " CellSetSingleType ShapeType " << this->CellShapeAsId << std::endl;
out << " VisitCellsWithPoints: " << std::endl;
this->Data->VisitCellsWithPoints.PrintSummary(out);
out << " VisitPointsWithCells: " << std::endl;
this->Data->VisitPointsWithCells.PrintSummary(out);
out << " CellSetSingleType: Type=" << this->CellShapeAsId << std::endl;
out << " CellPointIds:" << std::endl;
this->Data->CellPointIds.PrintSummary(out);
out << " PointCellIds:" << std::endl;
this->Data->PointCellIds.PrintSummary(out);
}
private:

@ -10,6 +10,8 @@
#ifndef vtk_m_cont_DataSetBuilderExplicit_h
#define vtk_m_cont_DataSetBuilderExplicit_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/CoordinateSystem.h>
@ -21,17 +23,9 @@ namespace cont
{
//Coordinates builder??
//Need a singlecellset handler.
class VTKM_CONT_EXPORT DataSetBuilderExplicit
{
template <typename T>
VTKM_CONT static void CopyInto(const std::vector<T>& input, vtkm::cont::ArrayHandle<T>& output)
{
output.Allocate(static_cast<vtkm::Id>(input.size()));
std::copy(input.begin(), input.end(), ArrayPortalToIteratorBegin(output.GetPortalControl()));
}
public:
VTKM_CONT
DataSetBuilderExplicit() {}
@ -84,8 +78,10 @@ public:
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm = "coords")
{
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
return DataSetBuilderExplicit::BuildDataSet(
xVals, yVals, zVals, shapes, numIndices, connectivity, coordsNm);
xVals, yVals, zVals, shapes, offsets, connectivity, coordsNm);
}
template <typename T>
@ -103,7 +99,8 @@ public:
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm = "coords")
{
return DataSetBuilderExplicit::BuildDataSet(coords, shapes, numIndices, connectivity, coordsNm);
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
return DataSetBuilderExplicit::BuildDataSet(coords, shapes, offsets, connectivity, coordsNm);
}
template <typename T, typename CellShapeTag>
@ -127,20 +124,19 @@ public:
private:
template <typename T>
static vtkm::cont::DataSet BuildDataSet(
const vtkm::cont::ArrayHandle<T>& X,
const vtkm::cont::ArrayHandle<T>& Y,
const vtkm::cont::ArrayHandle<T>& Z,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm);
static vtkm::cont::DataSet BuildDataSet(const vtkm::cont::ArrayHandle<T>& X,
const vtkm::cont::ArrayHandle<T>& Y,
const vtkm::cont::ArrayHandle<T>& Z,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
const vtkm::cont::ArrayHandle<vtkm::Id>& offsets,
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm);
template <typename T>
VTKM_CONT static vtkm::cont::DataSet BuildDataSet(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& coords,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id>& offsets,
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm);
@ -165,19 +161,18 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::Create(
{
VTKM_ASSERT(xVals.size() == yVals.size() && yVals.size() == zVals.size() && xVals.size() > 0);
vtkm::cont::ArrayHandle<T> Xc, Yc, Zc;
DataSetBuilderExplicit::CopyInto(xVals, Xc);
DataSetBuilderExplicit::CopyInto(yVals, Yc);
DataSetBuilderExplicit::CopyInto(zVals, Zc);
auto xArray = vtkm::cont::make_ArrayHandle(xVals, vtkm::CopyFlag::On);
auto yArray = vtkm::cont::make_ArrayHandle(yVals, vtkm::CopyFlag::On);
auto zArray = vtkm::cont::make_ArrayHandle(zVals, vtkm::CopyFlag::On);
vtkm::cont::ArrayHandle<vtkm::UInt8> Sc;
vtkm::cont::ArrayHandle<vtkm::IdComponent> Nc;
vtkm::cont::ArrayHandle<vtkm::Id> Cc;
DataSetBuilderExplicit::CopyInto(shapes, Sc);
DataSetBuilderExplicit::CopyInto(numIndices, Nc);
DataSetBuilderExplicit::CopyInto(connectivity, Cc);
auto shapesArray = vtkm::cont::make_ArrayHandle(shapes, vtkm::CopyFlag::On);
auto connArray = vtkm::cont::make_ArrayHandle(connectivity, vtkm::CopyFlag::On);
return DataSetBuilderExplicit::BuildDataSet(Xc, Yc, Zc, Sc, Nc, Cc, coordsNm);
auto offsetsArray = vtkm::cont::ConvertNumIndicesToOffsets(
vtkm::cont::make_ArrayHandle(numIndices, vtkm::CopyFlag::Off));
return DataSetBuilderExplicit::BuildDataSet(
xArray, yArray, zArray, shapesArray, offsetsArray, connArray, coordsNm);
}
template <typename T>
@ -186,13 +181,13 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::BuildDataSet(
const vtkm::cont::ArrayHandle<T>& Y,
const vtkm::cont::ArrayHandle<T>& Z,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id>& offsets,
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm)
{
VTKM_ASSERT(X.GetNumberOfValues() == Y.GetNumberOfValues() &&
Y.GetNumberOfValues() == Z.GetNumberOfValues() && X.GetNumberOfValues() > 0 &&
shapes.GetNumberOfValues() == numIndices.GetNumberOfValues());
shapes.GetNumberOfValues() + 1 == offsets.GetNumberOfValues());
vtkm::cont::DataSet dataSet;
dataSet.AddCoordinateSystem(
@ -200,7 +195,7 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::BuildDataSet(
vtkm::Id nPts = X.GetNumberOfValues();
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(nPts, shapes, numIndices, connectivity);
cellSet.Fill(nPts, shapes, connectivity, offsets);
dataSet.SetCellSet(cellSet);
return dataSet;
@ -214,24 +209,22 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::Create(
const std::vector<vtkm::Id>& connectivity,
const std::string& coordsNm)
{
vtkm::cont::ArrayHandle<Vec<T, 3>> coordsArray;
DataSetBuilderExplicit::CopyInto(coords, coordsArray);
auto coordsArray = vtkm::cont::make_ArrayHandle(coords, vtkm::CopyFlag::On);
auto shapesArray = vtkm::cont::make_ArrayHandle(shapes, vtkm::CopyFlag::On);
auto connArray = vtkm::cont::make_ArrayHandle(connectivity, vtkm::CopyFlag::On);
vtkm::cont::ArrayHandle<vtkm::UInt8> Sc;
vtkm::cont::ArrayHandle<vtkm::IdComponent> Nc;
vtkm::cont::ArrayHandle<vtkm::Id> Cc;
DataSetBuilderExplicit::CopyInto(shapes, Sc);
DataSetBuilderExplicit::CopyInto(numIndices, Nc);
DataSetBuilderExplicit::CopyInto(connectivity, Cc);
auto offsetsArray = vtkm::cont::ConvertNumIndicesToOffsets(
vtkm::cont::make_ArrayHandle(numIndices, vtkm::CopyFlag::Off));
return DataSetBuilderExplicit::Create(coordsArray, Sc, Nc, Cc, coordsNm);
return DataSetBuilderExplicit::BuildDataSet(
coordsArray, shapesArray, offsetsArray, connArray, coordsNm);
}
template <typename T>
inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::BuildDataSet(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& coords,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices,
const vtkm::cont::ArrayHandle<vtkm::Id>& offsets,
const vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
const std::string& coordsNm)
{
@ -241,7 +234,7 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::BuildDataSet(
vtkm::Id nPts = static_cast<vtkm::Id>(coords.GetNumberOfValues());
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(nPts, shapes, numIndices, connectivity);
cellSet.Fill(nPts, shapes, connectivity, offsets);
dataSet.SetCellSet(cellSet);
return dataSet;
@ -255,13 +248,11 @@ inline VTKM_CONT vtkm::cont::DataSet DataSetBuilderExplicit::Create(
const std::vector<vtkm::Id>& connectivity,
const std::string& coordsNm)
{
vtkm::cont::ArrayHandle<Vec<T, 3>> coordsArray;
DataSetBuilderExplicit::CopyInto(coords, coordsArray);
auto coordsArray = vtkm::cont::make_ArrayHandle(coords, vtkm::CopyFlag::On);
auto connArray = vtkm::cont::make_ArrayHandle(connectivity, vtkm::CopyFlag::On);
vtkm::cont::ArrayHandle<vtkm::Id> Cc;
DataSetBuilderExplicit::CopyInto(connectivity, Cc);
return DataSetBuilderExplicit::Create(coordsArray, tag, numberOfPointsPerCell, Cc, coordsNm);
return DataSetBuilderExplicit::Create(
coordsArray, tag, numberOfPointsPerCell, connArray, coordsNm);
}
template <typename T, typename CellShapeTag>

@ -134,7 +134,7 @@ struct DeviceAdapterAlgorithm
template <typename WordType>
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word, vtkm::Id numBits);
template <typename WordType>
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word, bool value);
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word);
/// @}
/// Fill @a array with @a value. If @a numValues is specified, the array will
@ -253,16 +253,6 @@ struct DeviceAdapterAlgorithm
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output);
/// \brief Streaming version of scan exclusive
///
/// Computes a scan one block at a time.
///
/// \return The total sum.
///
template <typename T, class CIn, class COut>
VTKM_CONT static T StreamingScanExclusive(const vtkm::Id numBlocks,
const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output);
/// \brief Compute an inclusive prefix sum operation on the input ArrayHandle.
///
@ -378,6 +368,17 @@ struct DeviceAdapterAlgorithm
const vtkm::cont::ArrayHandle<U, VIn>& values,
vtkm::cont::ArrayHandle<U, VOut>& output);
/// \brief Streaming version of scan exclusive
///
/// Computes a scan one block at a time.
///
/// \return The total sum.
///
template <typename T, class CIn, class COut>
VTKM_CONT static T StreamingScanExclusive(const vtkm::Id numBlocks,
const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output);
/// \brief Compute an extended prefix sum operation on the input ArrayHandle.
///
/// Computes an extended prefix sum operation on the \c input ArrayHandle,

@ -22,6 +22,13 @@ namespace vtkm
namespace cont
{
namespace detail
{
template <typename T>
using scatter_or_mask = std::integral_constant<bool,
vtkm::worklet::internal::is_mask<T>::value ||
vtkm::worklet::internal::is_scatter<T>::value>;
}
/// \brief Allows launching any worklet without a dispatcher.
///
@ -53,40 +60,59 @@ struct Invoker
}
/// Launch the worklet that is provided as the first parameter.
/// Optional second parameter is the scatter type associated with the worklet.
/// Optional second parameter is either the scatter or mask type associated with the worklet.
/// Any additional parameters are the ControlSignature arguments for the worklet.
///
template <
typename Worklet,
typename T,
typename... Args,
typename std::enable_if<std::is_base_of<worklet::internal::ScatterBase,
worklet::internal::detail::remove_cvref<T>>::value,
int>::type* = nullptr>
inline void operator()(Worklet&& worklet, T&& scatter, Args&&... args) const
template <typename Worklet,
typename T,
typename... Args,
typename std::enable_if<detail::scatter_or_mask<T>::value, int>::type* = nullptr>
inline void operator()(Worklet&& worklet, T&& scatterOrMask, Args&&... args) const
{
using WorkletType = worklet::internal::detail::remove_cvref<Worklet>;
using WorkletType = worklet::internal::remove_cvref<Worklet>;
using DispatcherType = typename WorkletType::template Dispatcher<WorkletType>;
DispatcherType dispatcher(worklet, scatter);
DispatcherType dispatcher(worklet, scatterOrMask);
dispatcher.SetDevice(this->DeviceId);
dispatcher.Invoke(std::forward<Args>(args)...);
}
/// Launch the worklet that is provided as the first parameter.
/// Optional second parameter is the scatter type associated with the worklet.
/// Optional second parameter is either the scatter or mask type associated with the worklet.
/// Optional third parameter is either the scatter or mask type associated with the worklet.
/// Any additional parameters are the ControlSignature arguments for the worklet.
///
template <
typename Worklet,
typename T,
typename U,
typename... Args,
typename std::enable_if<!std::is_base_of<worklet::internal::ScatterBase,
worklet::internal::detail::remove_cvref<T>>::value,
typename std::enable_if<detail::scatter_or_mask<T>::value && detail::scatter_or_mask<U>::value,
int>::type* = nullptr>
inline void operator()(Worklet&& worklet,
T&& scatterOrMaskA,
U&& scatterOrMaskB,
Args&&... args) const
{
using WorkletType = worklet::internal::remove_cvref<Worklet>;
using DispatcherType = typename WorkletType::template Dispatcher<WorkletType>;
DispatcherType dispatcher(worklet, scatterOrMaskA, scatterOrMaskB);
dispatcher.SetDevice(this->DeviceId);
dispatcher.Invoke(std::forward<Args>(args)...);
}
/// Launch the worklet that is provided as the first parameter.
/// Optional second parameter is either the scatter or mask type associated with the worklet.
/// Any additional parameters are the ControlSignature arguments for the worklet.
///
template <typename Worklet,
typename T,
typename... Args,
typename std::enable_if<!detail::scatter_or_mask<T>::value, int>::type* = nullptr>
inline void operator()(Worklet&& worklet, T&& t, Args&&... args) const
{
using WorkletType = worklet::internal::detail::remove_cvref<Worklet>;
using WorkletType = worklet::internal::remove_cvref<Worklet>;
using DispatcherType = typename WorkletType::template Dispatcher<WorkletType>;
DispatcherType dispatcher(worklet);

@ -111,6 +111,7 @@ void InitLogging(int& argc, char* argv[])
SetLogLevelName(vtkm::cont::LogLevel::Error, "ERR");
SetLogLevelName(vtkm::cont::LogLevel::Warn, "WARN");
SetLogLevelName(vtkm::cont::LogLevel::Info, "Info");
SetLogLevelName(vtkm::cont::LogLevel::DevicesEnabled, "Dev");
SetLogLevelName(vtkm::cont::LogLevel::Perf, "Perf");
SetLogLevelName(vtkm::cont::LogLevel::MemCont, "MemC");
SetLogLevelName(vtkm::cont::LogLevel::MemExec, "MemE");

@ -322,6 +322,9 @@ enum class LogLevel
/// The range 1-255 are reserved to application use.
UserLast = 255,
/// Information about which devices are enabled/disabled
DevicesEnabled,
/// General timing data and algorithm flow information, such as filter
/// execution, worklet dispatches, and device algorithm calls.
Perf,
@ -482,9 +485,9 @@ static inline VTKM_CONT std::string TypeToString()
return TypeToString(typeid(T));
}
template <typename T>
static inline VTKM_CONT std::string TypeToString(const T& t)
static inline VTKM_CONT std::string TypeToString(const T&)
{
return TypeToString(typeid(t));
return TypeToString(typeid(T));
}
/**@}*/
}

@ -86,8 +86,6 @@ void RuntimeDeviceTracker::SetDeviceState(vtkm::cont::DeviceAdapterId deviceId,
{
this->CheckDevice(deviceId);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Setting device '" << deviceId.GetName() << "' to " << state);
this->Internals->RuntimeAllowed[deviceId.GetValue()] = state;
}
@ -102,6 +100,7 @@ VTKM_CONT void RuntimeDeviceTracker::ResetDevice(vtkm::cont::DeviceAdapterId dev
{
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
this->SetDeviceState(deviceId, runtimeDevice.Exists(deviceId));
this->LogEnabledDevices();
}
}
@ -122,10 +121,9 @@ void RuntimeDeviceTracker::Reset()
{
const bool state = runtimeDevice.Exists(device);
this->Internals->RuntimeAllowed[device.GetValue()] = state;
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Reset device '" << device.GetName() << "' to " << state);
}
}
this->LogEnabledDevices();
}
VTKM_CONT void RuntimeDeviceTracker::DisableDevice(vtkm::cont::DeviceAdapterId deviceId)
@ -138,6 +136,7 @@ VTKM_CONT void RuntimeDeviceTracker::DisableDevice(vtkm::cont::DeviceAdapterId d
{
this->SetDeviceState(deviceId, false);
}
this->LogEnabledDevices();
}
VTKM_CONT
@ -160,12 +159,10 @@ void RuntimeDeviceTracker::ForceDevice(DeviceAdapterId deviceId)
throw vtkm::cont::ErrorBadValue(message.str());
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Forcing execution to occur on device '" << deviceId.GetName() << "'");
std::fill_n(this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, false);
this->Internals->RuntimeAllowed[deviceId.GetValue()] = runtimeExists;
this->LogEnabledDevices();
}
}
@ -180,12 +177,35 @@ void RuntimeDeviceTracker::PrintSummary(std::ostream& out) const
}
}
VTKM_CONT
void RuntimeDeviceTracker::LogEnabledDevices() const
{
std::stringstream message;
message << "Enabled devices:";
bool atLeastOneDeviceEnabled = false;
for (vtkm::Int8 deviceIndex = 1; deviceIndex < VTKM_MAX_DEVICE_ADAPTER_ID; ++deviceIndex)
{
vtkm::cont::DeviceAdapterId device = vtkm::cont::make_DeviceAdapterId(deviceIndex);
if (this->CanRunOn(device))
{
message << " " << device.GetName();
atLeastOneDeviceEnabled = true;
}
}
if (!atLeastOneDeviceEnabled)
{
message << " NONE!";
}
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, message.str());
}
VTKM_CONT
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode)
: RuntimeDeviceTracker(GetRuntimeDeviceTracker().Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Entering scoped runtime region");
std::copy_n(
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
@ -211,6 +231,7 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
: RuntimeDeviceTracker(tracker.Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Entering scoped runtime region");
std::copy_n(
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
if (mode == RuntimeDeviceTrackerMode::Force)
@ -233,6 +254,7 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
: RuntimeDeviceTracker(tracker.Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Entering scoped runtime region");
std::copy_n(
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
}
@ -240,8 +262,10 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
VTKM_CONT
ScopedRuntimeDeviceTracker::~ScopedRuntimeDeviceTracker()
{
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Leaving scoped runtime region");
std::copy_n(
this->SavedState->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->Internals->RuntimeAllowed);
this->LogEnabledDevices();
}
VTKM_CONT

@ -131,6 +131,9 @@ private:
VTKM_CONT
void SetDeviceState(vtkm::cont::DeviceAdapterId deviceId, bool state);
VTKM_CONT
void LogEnabledDevices() const;
};

@ -22,7 +22,6 @@ set(headers
ConnectivityExplicitInternals.h
DeviceAdapterAlgorithmGeneral.h
DeviceAdapterListHelpers.h
DynamicTransform.h
FunctorsGeneral.h
IteratorFromArrayPortal.h
KXSort.h

@ -12,6 +12,7 @@
#include <vtkm/CellShape.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayGetValues.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleConstant.h>
@ -26,67 +27,24 @@ namespace cont
namespace internal
{
template <typename NumIndicesArrayType, typename IndexOffsetArrayType>
void buildIndexOffsets(const NumIndicesArrayType& numIndices,
IndexOffsetArrayType& offsets,
vtkm::cont::DeviceAdapterId device,
std::true_type)
{
//We first need to make sure that NumIndices and IndexOffsetArrayType
//have the same type so we can call scane exclusive
using CastedNumIndicesType = vtkm::cont::ArrayHandleCast<vtkm::Id, NumIndicesArrayType>;
// Although technically we are making changes to this object, the changes
// are logically consistent with the previous state, so we consider it
// valid under const.
vtkm::cont::Algorithm::ScanExclusive(device, CastedNumIndicesType(numIndices), offsets);
}
template <typename NumIndicesArrayType, typename IndexOffsetArrayType>
void buildIndexOffsets(const NumIndicesArrayType&,
IndexOffsetArrayType&,
vtkm::cont::DeviceAdapterId,
std::false_type)
{
//this is a no-op as the storage for the offsets is an implicit handle
//and should already be built. This signature exists so that
//the compiler doesn't try to generate un-used code that will
//try and run Algorithm::ScanExclusive on an implicit array which will
//cause a compile time failure.
}
template <typename ArrayHandleIndices, typename ArrayHandleOffsets>
void buildIndexOffsets(const ArrayHandleIndices& numIndices,
ArrayHandleOffsets offsets,
vtkm::cont::DeviceAdapterId deviceId)
{
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<ArrayHandleOffsets>;
buildIndexOffsets(numIndices, offsets, deviceId, typename IsWritable::type());
}
template <typename ShapeStorageTag = VTKM_DEFAULT_STORAGE_TAG,
typename NumIndicesStorageTag = VTKM_DEFAULT_STORAGE_TAG,
template <typename ShapesStorageTag = VTKM_DEFAULT_STORAGE_TAG,
typename ConnectivityStorageTag = VTKM_DEFAULT_STORAGE_TAG,
typename IndexOffsetStorageTag = VTKM_DEFAULT_STORAGE_TAG>
typename OffsetsStorageTag = VTKM_DEFAULT_STORAGE_TAG>
struct ConnectivityExplicitInternals
{
using ShapeArrayType = vtkm::cont::ArrayHandle<vtkm::UInt8, ShapeStorageTag>;
using NumIndicesArrayType = vtkm::cont::ArrayHandle<vtkm::IdComponent, NumIndicesStorageTag>;
using ShapesArrayType = vtkm::cont::ArrayHandle<vtkm::UInt8, ShapesStorageTag>;
using ConnectivityArrayType = vtkm::cont::ArrayHandle<vtkm::Id, ConnectivityStorageTag>;
using IndexOffsetArrayType = vtkm::cont::ArrayHandle<vtkm::Id, IndexOffsetStorageTag>;
using OffsetsArrayType = vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>;
ShapeArrayType Shapes;
NumIndicesArrayType NumIndices;
ShapesArrayType Shapes;
ConnectivityArrayType Connectivity;
mutable IndexOffsetArrayType IndexOffsets;
OffsetsArrayType Offsets;
bool ElementsValid;
mutable bool IndexOffsetsValid;
VTKM_CONT
ConnectivityExplicitInternals()
: ElementsValid(false)
, IndexOffsetsValid(false)
{
}
@ -102,26 +60,8 @@ struct ConnectivityExplicitInternals
void ReleaseResourcesExecution()
{
this->Shapes.ReleaseResourcesExecution();
this->NumIndices.ReleaseResourcesExecution();
this->Connectivity.ReleaseResourcesExecution();
this->IndexOffsets.ReleaseResourcesExecution();
}
VTKM_CONT void BuildIndexOffsets(vtkm::cont::DeviceAdapterId deviceId) const
{
if (deviceId == vtkm::cont::DeviceAdapterTagUndefined())
{
throw vtkm::cont::ErrorBadValue("Cannot build indices using DeviceAdapterTagUndefined");
}
VTKM_ASSERT(this->ElementsValid);
if (!this->IndexOffsetsValid)
{
buildIndexOffsets(this->NumIndices, this->IndexOffsets, deviceId);
this->IndexOffsetsValid = true;
}
this->Offsets.ReleaseResourcesExecution();
}
VTKM_CONT
@ -131,19 +71,10 @@ struct ConnectivityExplicitInternals
{
out << " Shapes: ";
vtkm::cont::printSummary_ArrayHandle(this->Shapes, out);
out << " NumIndices: ";
vtkm::cont::printSummary_ArrayHandle(this->NumIndices, out);
out << " Connectivity: ";
vtkm::cont::printSummary_ArrayHandle(this->Connectivity, out);
if (this->IndexOffsetsValid)
{
out << " IndexOffsets: ";
vtkm::cont::printSummary_ArrayHandle(this->IndexOffsets, out);
}
else
{
out << " IndexOffsets: Not Allocated" << std::endl;
}
out << " Offsets: ";
vtkm::cont::printSummary_ArrayHandle(this->Offsets, out);
}
else
{
@ -225,95 +156,73 @@ struct ConnIdxToCellIdCalcSingleType
vtkm::Id operator()(vtkm::Id inIdx) const { return inIdx / this->CellSize; }
};
template <typename VisitCellsWithPoints, typename VisitPointsWithCells, typename Device>
void ComputeVisitPointsWithCellsConnectivity(VisitPointsWithCells& cell2Point,
const VisitCellsWithPoints& point2Cell,
vtkm::Id numberOfPoints,
Device)
template <typename ConnTableT, typename RConnTableT, typename Device>
void ComputeRConnTable(RConnTableT& rConnTable,
const ConnTableT& connTable,
vtkm::Id numberOfPoints,
Device)
{
if (cell2Point.ElementsValid)
if (rConnTable.ElementsValid)
{
return;
}
auto& conn = point2Cell.Connectivity;
auto& rConn = cell2Point.Connectivity;
auto& rNumIndices = cell2Point.NumIndices;
auto& rIndexOffsets = cell2Point.IndexOffsets;
vtkm::Id rConnSize = conn.GetNumberOfValues();
const auto& conn = connTable.Connectivity;
auto& rConn = rConnTable.Connectivity;
auto& rOffsets = rConnTable.Offsets;
const vtkm::Id rConnSize = conn.GetNumberOfValues();
auto offInPortal = point2Cell.IndexOffsets.PrepareForInput(Device{});
const auto offInPortal = connTable.Offsets.PrepareForInput(Device{});
PassThrough idxCalc{};
ConnIdxToCellIdCalc<decltype(offInPortal)> cellIdCalc{ offInPortal };
vtkm::cont::internal::ReverseConnectivityBuilder builder;
builder.Run(conn,
rConn,
rNumIndices,
rIndexOffsets,
idxCalc,
cellIdCalc,
numberOfPoints,
rConnSize,
Device());
builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, Device());
// Set the VisitPointsWithCells information
cell2Point.Shapes = vtkm::cont::make_ArrayHandleConstant(
rConnTable.Shapes = vtkm::cont::make_ArrayHandleConstant(
static_cast<vtkm::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
cell2Point.ElementsValid = true;
cell2Point.IndexOffsetsValid = true;
rConnTable.ElementsValid = true;
}
// Specialize for CellSetSingleType:
template <typename ShapeStorageTag,
typename ConnectivityStorageTag,
typename IndexOffsetStorageTag,
typename VisitPointsWithCells,
typename Device>
void ComputeVisitPointsWithCellsConnectivity(
VisitPointsWithCells& cell2Point,
const ConnectivityExplicitInternals<
ShapeStorageTag,
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>::StorageTag, // nIndices
ConnectivityStorageTag,
IndexOffsetStorageTag>& point2Cell,
vtkm::Id numberOfPoints,
Device)
template <typename RConnTableT, typename ConnectivityStorageTag, typename Device>
void ComputeRConnTable(RConnTableT& rConnTable,
const ConnectivityExplicitInternals< // SingleType specialization types:
typename vtkm::cont::ArrayHandleConstant<vtkm::UInt8>::StorageTag,
ConnectivityStorageTag,
typename vtkm::cont::ArrayHandleCounting<vtkm::Id>::StorageTag>& connTable,
vtkm::Id numberOfPoints,
Device)
{
if (cell2Point.ElementsValid)
if (rConnTable.ElementsValid)
{
return;
}
auto& conn = point2Cell.Connectivity;
auto& rConn = cell2Point.Connectivity;
auto& rNumIndices = cell2Point.NumIndices;
auto& rIndexOffsets = cell2Point.IndexOffsets;
vtkm::Id rConnSize = conn.GetNumberOfValues();
const auto& conn = connTable.Connectivity;
auto& rConn = rConnTable.Connectivity;
auto& rOffsets = rConnTable.Offsets;
const vtkm::Id rConnSize = conn.GetNumberOfValues();
auto sizesInPortal = point2Cell.NumIndices.GetPortalConstControl();
vtkm::IdComponent cellSize = sizesInPortal.GetNumberOfValues() > 0 ? sizesInPortal.Get(0) : 0;
const vtkm::IdComponent cellSize = [&]() -> vtkm::IdComponent {
if (connTable.Offsets.GetNumberOfValues() >= 2)
{
const auto firstTwo = vtkm::cont::ArrayGetValues({ 0, 1 }, connTable.Offsets);
return static_cast<vtkm::IdComponent>(firstTwo[1] - firstTwo[0]);
}
return 0;
}();
PassThrough idxCalc{};
ConnIdxToCellIdCalcSingleType cellIdCalc{ cellSize };
vtkm::cont::internal::ReverseConnectivityBuilder builder;
builder.Run(conn,
rConn,
rNumIndices,
rIndexOffsets,
idxCalc,
cellIdCalc,
numberOfPoints,
rConnSize,
Device());
builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, Device());
// Set the VisitPointsWithCells information
cell2Point.Shapes = vtkm::cont::make_ArrayHandleConstant(
rConnTable.Shapes = vtkm::cont::make_ArrayHandleConstant(
static_cast<vtkm::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
cell2Point.ElementsValid = true;
cell2Point.IndexOffsetsValid = true;
rConnTable.ElementsValid = true;
}
}
}

@ -1,62 +0,0 @@
//============================================================================
// 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_internal_DynamicTransform_h
#define vtk_m_cont_internal_DynamicTransform_h
#include <vtkm/cont/CastAndCall.h>
#include <vtkm/internal/IndexTag.h>
#include <utility>
namespace vtkm
{
namespace cont
{
namespace internal
{
/// This functor can be used as the transform in the \c DynamicTransformCont
/// method of \c FunctionInterface. It will allow dynamic objects like
/// \c DynamicArray to be cast to their concrete types for templated operation.
///
struct DynamicTransform
{
template <typename InputType, typename ContinueFunctor, vtkm::IdComponent Index>
VTKM_CONT void operator()(const InputType& input,
const ContinueFunctor& continueFunc,
vtkm::internal::IndexTag<Index>) const
{
this->DoTransform(
input,
continueFunc,
typename vtkm::cont::internal::DynamicTransformTraits<InputType>::DynamicTag());
}
private:
template <typename InputType, typename ContinueFunctor>
VTKM_CONT void DoTransform(const InputType& input,
const ContinueFunctor& continueFunc,
vtkm::cont::internal::DynamicTransformTagStatic) const
{
continueFunc(input);
}
template <typename InputType, typename ContinueFunctor>
VTKM_CONT void DoTransform(const InputType& dynamicInput,
const ContinueFunctor& continueFunc,
vtkm::cont::internal::DynamicTransformTagCastAndCall) const
{
CastAndCall(dynamicInput, continueFunc);
}
};
}
}
} // namespace vtkm::cont::internal
#endif //vtk_m_cont_internal_DynamicTransform_h

@ -131,15 +131,13 @@ public:
VTKM_CONT
template <typename ConnArray,
typename RConnArray,
typename RNumArray,
typename RIndexArray,
typename ROffsetsArray,
typename RConnToConnIdxCalc,
typename ConnIdxToCellIdxCalc,
typename Device>
inline void Run(const ConnArray& conn,
RConnArray& rConn,
RNumArray& rNumIndices,
RIndexArray& rIndexOffsets,
ROffsetsArray& rOffsets,
const RConnToConnIdxCalc& rConnToConnCalc,
const ConnIdxToCellIdxCalc& cellIdCalc,
vtkm::Id numberOfPoints,
@ -152,12 +150,13 @@ public:
auto zeros = vtkm::cont::make_ArrayHandleConstant(vtkm::IdComponent{ 0 }, numberOfPoints);
// Compute RConn offsets by atomically building a histogram and doing an
// exclusive scan.
// extended scan.
//
// Example:
// (in) Conn: | 3 0 1 2 | 3 0 1 3 | 3 0 3 4 | 3 3 4 5 |
// (out) RNumIndices: 3 2 1 3 2 1
// (out) RIdxOffsets: 0 3 5 6 9 11
// (out) RIdxOffsets: 0 3 5 6 9 11 12
vtkm::cont::ArrayHandle<vtkm::IdComponent> rNumIndices;
{ // allocate and zero the numIndices array:
Algo::Copy(zeros, rNumIndices);
}
@ -165,17 +164,15 @@ public:
{ // Build histogram:
vtkm::cont::AtomicArray<vtkm::IdComponent> atomicCounter{ rNumIndices };
auto ac = atomicCounter.PrepareForExecution(Device());
rcb::BuildHistogram<decltype(ac), decltype(connPortal), RConnToConnIdxCalc> histoGen{
ac, connPortal, rConnToConnCalc
};
using BuildHisto =
rcb::BuildHistogram<decltype(ac), decltype(connPortal), RConnToConnIdxCalc>;
BuildHisto histoGen{ ac, connPortal, rConnToConnCalc };
Algo::Schedule(histoGen, rConnSize);
}
{ // Compute offsets:
auto rNumIndicesAsId =
vtkm::cont::make_ArrayHandleCast<typename RIndexArray::ValueType>(rNumIndices);
Algo::ScanExclusive(rNumIndicesAsId, rIndexOffsets);
Algo::ScanExtended(vtkm::cont::make_ArrayHandleCast<vtkm::Id>(rNumIndices), rOffsets);
}
{ // Reset the numIndices array to 0's:
@ -198,16 +195,16 @@ public:
{
vtkm::cont::AtomicArray<vtkm::IdComponent> atomicCounter{ rNumIndices };
auto ac = atomicCounter.PrepareForExecution(Device());
auto rOffsetPortal = rIndexOffsets.PrepareForInput(Device());
auto rOffsetPortal = rOffsets.PrepareForInput(Device());
auto rConnPortal = rConn.PrepareForOutput(rConnSize, Device());
rcb::GenerateRConn<decltype(ac),
decltype(connPortal),
decltype(rOffsetPortal),
decltype(rConnPortal),
RConnToConnIdxCalc,
ConnIdxToCellIdxCalc>
rConnGen{ ac, connPortal, rOffsetPortal, rConnPortal, rConnToConnCalc, cellIdCalc };
using GenRConnT = rcb::GenerateRConn<decltype(ac),
decltype(connPortal),
decltype(rOffsetPortal),
decltype(rConnPortal),
RConnToConnIdxCalc,
ConnIdxToCellIdxCalc>;
GenRConnT rConnGen{ ac, connPortal, rOffsetPortal, rConnPortal, rConnToConnCalc, cellIdCalc };
Algo::Schedule(rConnGen, rConnSize);
}

@ -12,7 +12,6 @@
set(unit_tests
UnitTestArrayManagerExecutionShareWithControl.cxx
UnitTestArrayPortalFromIterators.cxx
UnitTestDynamicTransform.cxx
UnitTestIteratorFromArrayPortal.cxx
)
vtkm_unit_tests(SOURCES ${unit_tests} DEFINES VTKM_NO_ERROR_ON_MIXED_CUDA_CXX_TAG)

@ -1,196 +0,0 @@
//============================================================================
// 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/internal/DynamicTransform.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <vtkm/internal/FunctionInterface.h>
#include <vtkm/cont/testing/Testing.h>
namespace vtkm
{
// VariantArrayHandle requires its value type to have a defined VecTraits
// class. One of the tests is to use an "unusual" array of std::string
// (which is pretty pointless but might tease out some assumptions).
// Make an implementation here. Because I am lazy, this is only a partial
// implementation.
template <>
struct VecTraits<std::string>
{
using IsSizeStatic = vtkm::VecTraitsTagSizeStatic;
static constexpr vtkm::IdComponent NUM_COMPONENTS = 1;
using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent;
};
} // namespace vtkm
namespace
{
static int g_FunctionCalls;
#define TRY_TRANSFORM(expr) \
g_FunctionCalls = 0; \
expr; \
VTKM_TEST_ASSERT(g_FunctionCalls == 1, "Functor not called correctly.")
struct TypeListTagString : vtkm::ListTagBase<std::string>
{
};
struct ScalarFunctor
{
void operator()(vtkm::FloatDefault) const
{
std::cout << " In Scalar functor." << std::endl;
g_FunctionCalls++;
}
};
struct ArrayHandleScalarFunctor
{
template <typename ArrayType>
void operator()(const ArrayType&) const
{
VTKM_TEST_FAIL("Called wrong form of functor operator.");
}
void operator()(const vtkm::cont::ArrayHandleVirtual<vtkm::FloatDefault>&) const
{
std::cout << " In ArrayHandleVirtual<Scalar> functor." << std::endl;
g_FunctionCalls++;
}
void operator()(const vtkm::cont::ArrayHandle<vtkm::FloatDefault>&) const
{
std::cout << " In ArrayHandle<Scalar> functor." << std::endl;
g_FunctionCalls++;
}
};
struct ArrayHandleStringFunctor
{
void operator()(const vtkm::cont::ArrayHandleVirtual<std::string>&) const
{
std::cout << " In ArrayHandleVirtual<string> functor." << std::endl;
g_FunctionCalls++;
}
};
struct CellSetStructuredFunctor
{
template <typename T>
void operator()(const T&) const
{
VTKM_TEST_FAIL("Called wrong form of functor operator.");
}
void operator()(const vtkm::cont::CellSetStructured<3>&) const
{
std::cout << " In CellSetStructured<3> functor." << std::endl;
g_FunctionCalls++;
}
};
struct FunctionInterfaceFunctor
{
template <typename Signature>
void operator()(const vtkm::internal::FunctionInterface<Signature>&) const
{
VTKM_TEST_FAIL("Called wrong form of functor operator.");
}
void operator()(
const vtkm::internal::FunctionInterface<void(vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<std::string>,
vtkm::cont::CellSetStructured<3>)>&) const
{
std::cout << " In FunctionInterface<...> functor." << std::endl;
g_FunctionCalls++;
}
void operator()(
const vtkm::internal::FunctionInterface<void(vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandleVirtual<vtkm::FloatDefault>,
vtkm::cont::ArrayHandleVirtual<std::string>,
vtkm::cont::CellSetStructured<3>)>&) const
{
std::cout << " In FunctionInterface<...> functor." << std::endl;
g_FunctionCalls++;
}
};
void TestBasicTransform()
{
std::cout << "Testing basic transform." << std::endl;
vtkm::cont::internal::DynamicTransform transform;
vtkm::internal::IndexTag<1> indexTag;
std::cout << " Trying with simple scalar." << std::endl;
TRY_TRANSFORM(transform(vtkm::FloatDefault(5), ScalarFunctor(), indexTag));
std::cout << " Trying with basic scalar array." << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> concreteArray;
TRY_TRANSFORM(transform(concreteArray, ArrayHandleScalarFunctor(), indexTag));
std::cout << " Trying scalar dynamic array." << std::endl;
vtkm::cont::VariantArrayHandle dynamicArray = concreteArray;
TRY_TRANSFORM(transform(dynamicArray, ArrayHandleScalarFunctor(), indexTag));
std::cout << " Trying with unusual (string) dynamic array." << std::endl;
dynamicArray = vtkm::cont::ArrayHandle<std::string>();
TRY_TRANSFORM(
transform(dynamicArray.ResetTypes(TypeListTagString()), ArrayHandleStringFunctor(), indexTag));
std::cout << " Trying with structured cell set." << std::endl;
vtkm::cont::CellSetStructured<3> concreteCellSet;
TRY_TRANSFORM(transform(concreteCellSet, CellSetStructuredFunctor(), indexTag));
std::cout << " Trying with dynamic cell set." << std::endl;
vtkm::cont::DynamicCellSet dynamicCellSet = concreteCellSet;
TRY_TRANSFORM(transform(dynamicCellSet, CellSetStructuredFunctor(), indexTag));
}
void TestFunctionTransform()
{
std::cout << "Testing transforms in FunctionInterface." << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> scalarArray;
vtkm::cont::ArrayHandle<std::string> stringArray;
vtkm::cont::CellSetStructured<3> structuredCellSet;
std::cout << " Trying basic functor call w/o transform (make sure it works)." << std::endl;
TRY_TRANSFORM(FunctionInterfaceFunctor()(vtkm::internal::make_FunctionInterface<void>(
scalarArray, scalarArray, stringArray, structuredCellSet)));
std::cout << " Trying dynamic cast" << std::endl;
TRY_TRANSFORM(
vtkm::internal::make_FunctionInterface<void>(
scalarArray,
vtkm::cont::VariantArrayHandle(scalarArray),
vtkm::cont::VariantArrayHandle(stringArray).ResetTypes(TypeListTagString()),
vtkm::cont::DynamicCellSet(structuredCellSet))
.DynamicTransformCont(vtkm::cont::internal::DynamicTransform(), FunctionInterfaceFunctor()));
}
void TestDynamicTransform()
{
TestBasicTransform();
TestFunctionTransform();
}
} // anonymous namespace
int UnitTestDynamicTransform(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestDynamicTransform, argc, argv);
}

@ -42,10 +42,10 @@
// 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
#if defined(VTKM_GCC) && (__GNUC__ < 9)
#define VTKM_OPENMP_SHARED_CONST(...)
#else
#define VTKM_OPENMP_SHARED_CONST(...) shared(__VA_ARGS__)
#endif
// When defined, supported type / operator combinations will use the OpenMP

@ -38,7 +38,7 @@ public:
template <class Func>
static VTKM_CONT int Run(Func function, int& argc, char* argv[])
{
vtkm::cont::Initialize(argc, argv);
vtkm::cont::Initialize(argc, argv, vtkm::cont::InitializeOptions::Strict);
try
{
@ -71,7 +71,8 @@ public:
template <class Func>
static VTKM_CONT int RunOnDevice(Func function, int argc, char* argv[])
{
auto opts = vtkm::cont::InitializeOptions::RequireDevice;
auto opts =
vtkm::cont::InitializeOptions::RequireDevice | vtkm::cont::InitializeOptions::Strict;
auto config = vtkm::cont::Initialize(argc, argv, opts);
try
@ -229,11 +230,10 @@ namespace detail
struct TestEqualCellSet
{
template <typename ShapeST, typename CountST, typename ConnectivityST, typename OffsetST>
void operator()(
const vtkm::cont::CellSetExplicit<ShapeST, CountST, ConnectivityST, OffsetST>& cs1,
const vtkm::cont::CellSetExplicit<ShapeST, CountST, ConnectivityST, OffsetST>& cs2,
TestEqualResult& result) const
template <typename ShapeST, typename ConnectivityST, typename OffsetST>
void operator()(const vtkm::cont::CellSetExplicit<ShapeST, ConnectivityST, OffsetST>& cs1,
const vtkm::cont::CellSetExplicit<ShapeST, ConnectivityST, OffsetST>& cs2,
TestEqualResult& result) const
{
vtkm::TopologyElementTagCell visitTopo{};
vtkm::TopologyElementTagPoint incidentTopo{};
@ -266,8 +266,8 @@ struct TestEqualCellSet
result.PushMessage("connectivity arrays don't match");
return;
}
result = test_equal_ArrayHandles(cs1.GetIndexOffsetArray(visitTopo, incidentTopo),
cs2.GetIndexOffsetArray(visitTopo, incidentTopo));
result = test_equal_ArrayHandles(cs1.GetOffsetsArray(visitTopo, incidentTopo),
cs2.GetOffsetsArray(visitTopo, incidentTopo));
if (!result)
{
result.PushMessage("offsets arrays don't match");

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