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

This commit is contained in:
Dave Pugmire 2023-03-30 13:35:35 -04:00
commit a5ad12a4f4
138 changed files with 4471 additions and 1524 deletions

@ -58,7 +58,7 @@
- .docker_image
.ubuntu2004_hip_kokkos: &ubuntu2004_hip_kokkos
image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20230125"
image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20230220"
extends:
- .docker_image
@ -96,7 +96,7 @@
when: on_success
- when: never
.run_spock_ci: &run_spock_ci
.run_crusher_ci: &run_crusher_ci
rules:
- if: '$CI_PROJECT_PATH == "ci/csc331_crusher/dev/vtk-m"'
when: on_success
@ -214,7 +214,7 @@ stages:
include:
- local: '/.gitlab/ci/ascent.yml'
- local: '/.gitlab/ci/spock.yml'
- local: '/.gitlab/ci/crusher.yml'
- local: '/.gitlab/ci/centos7.yml'
- local: '/.gitlab/ci/centos8.yml'
- local: '/.gitlab/ci/doxygen.yml'

@ -2,7 +2,7 @@
.ascent_gcc_cuda:
variables:
CCACHE_BASEDIR: "/gpfs/wolf/"
CCACHE_DIR: "/gpfs/wolf/proj-shared/csc331/vtk-m/ci/ccache/"
CCACHE_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/ccache"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_NOHASHDIR: "true"
@ -12,7 +12,7 @@
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_GENERATOR: "Ninja"
CUDAHOSTCXX: "g++"
CUSTOM_CI_BUILDS_DIR: "/gpfs/wolf/proj-shared/csc331/vtk-m/ci/runtime"
CUSTOM_CI_BUILDS_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/vtk-m"
VTKM_SETTINGS: cuda+ascent+ccache
JOB_MODULES: >-
@ -30,14 +30,18 @@
module purge
module load ${JOB_MODULES}
module list
export PATH="/gpfs/wolf/proj-shared/csc331/vtk-m/ci/utils:$PATH"
export PATH="/gpfs/wolf/csc331/scratch/vbolea/ci/utils:$PATH"
build:ascent_gcc_cuda:
stage: build
tags: [olcf, ascent, nobatch]
tags: [olcf, ascent, batch]
extends:
- .ascent_gcc_cuda
- .run_ascent_ci
- .cmake_build_artifacts
variables:
SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 -alloc_flags smt1
timeout: 125 minutes
before_script:
- *setup_env_ecpci
- ccache -z
@ -46,14 +50,16 @@ build:ascent_gcc_cuda:
- git-lfs install
- git-lfs pull lfs
script:
- CTEST_MAX_PARALLELISM=32 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
# Each Ascent (Summit) node has 172 threads (43 cores). SMT1 is needed to
# avoid L1 cache pollution among different processes. Thus, using 40 cores
# seems a reasonable choice which leaves a couple of cores for system processes.
- CTEST_MAX_PARALLELISM=40 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
- ctest -VV -S .gitlab/ci/ctest_configure.cmake
artifacts:
expire_in: 24 hours
when: always
paths:
- build/
timeout: 10 minutes
- GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c40 -bpacked:40 ctest -VV -S .gitlab/ci/ctest_build.cmake
after_script:
- *setup_env_ecpci
- ccache -s
- ctest -VV -S .gitlab/ci/ctest_submit_build.cmake
test:ascent_gcc_cuda:
stage: test
@ -67,17 +73,18 @@ test:ascent_gcc_cuda:
dependencies:
- build:ascent_gcc_cuda
variables:
SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 -alloc_flags gpudefault
# For tests we want to use a small number of proccesses, for some reason
# a higher parallelism number tend to results in test malfunctions.
CTEST_MAX_PARALLELISM: 4
# We need this to skip ctest_submit from being run inside a jsrun job
GITLAB_CI_EMULATION: 1
SCHEDULER_PARAMETERS: -P CSC331 -W 1:00 -nnodes 1 -alloc_flags gpudefault
timeout: 65 minutes
before_script:
- *setup_env_ecpci
script:
- jsrun -n1 -a1 -g1 -c42 ctest -VV -S .gitlab/ci/ctest_build.cmake
- CTEST_MAX_PARALLELISM=4 jsrun -n1 -a1 -g1 -c8 ctest -VV -S .gitlab/ci/ctest_test.cmake
- cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
- jsrun -n1 -a1 -g1 -c1 ctest -VV -S .gitlab/ci/ctest_test.cmake
after_script:
- *setup_env_ecpci
- ccache -s
- ctest -VV -S .gitlab/ci/ctest_submit_build.cmake
- ctest -VV -S .gitlab/ci/ctest_submit_test.cmake
timeout: 120 minutes

@ -45,7 +45,7 @@ build:centos8:
- build
- vtkm
- docker
- linux
- linux-x86_64
extends:
- .centos8
- .cmake_build_linux

30
.gitlab/ci/config/kokkos.sh Executable file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -x
WORKDIR="$1"
VERSION="$2"
shift 2
if [ ! -d "$WORKDIR" ] || [ -z "$VERSION" ]
then
echo "[E] missing args: Invoke as .gitlab/ci/config/kokkos.sh <WORKDIR> <VERSION> [extra_args]"
exit 1
fi
# Build and install Kokkos
curl -L "https://github.com/kokkos/kokkos/archive/refs/tags/$VERSION.tar.gz" \
| tar -C "$WORKDIR" -xzf -
cmake -S "$WORKDIR/kokkos-$VERSION" -B "$WORKDIR/kokkos_build" \
"-DCMAKE_BUILD_TYPE:STRING=release" \
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache" \
"-DCMAKE_CXX_STANDARD:STRING=14" \
"-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON" \
"-DKokkos_ENABLE_HIP:BOOL=ON" \
"-DKokkos_ENABLE_HIP_RELOCATABLE_DEVICE_CODE:BOOL=OFF" \
"-DKokkos_ENABLE_SERIAL:BOOL=ON" \
$*
cmake --build "$WORKDIR/kokkos_build"
cmake --install "$WORKDIR/kokkos_build"

@ -1,9 +1,9 @@
# Ad-hoc build that runs in the ECP Hardware, concretely in OLCF Spock.
.spock_gcc_hip:
.crusher_gcc_hip:
variables:
CCACHE_BASEDIR: "/gpfs/alpine/world-shared/csc331/"
CCACHE_DIR: "/gpfs/alpine/world-shared/csc331/vtk-m/ci/ccache"
CUSTOM_CI_BUILDS_DIR: "/gpfs/alpine/world-shared/csc331/vtk-m/ci/runtime"
CCACHE_BASEDIR: "/gpfs/alpine/csc331/scratch/"
CCACHE_DIR: "/gpfs/alpine/csc331/scratch/vbolea/ci/vtk-m/ccache"
CUSTOM_CI_BUILDS_DIR: "/gpfs/alpine/csc331/scratch/vbolea/ci/vtk-m/runtime"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
@ -12,35 +12,25 @@
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_GENERATOR: "Ninja"
CMAKE_PREFIX_PATH: "$CI_BUILDS_DIR/kokkos_install"
# This is needed for the smoke_test, while we use rocm 5 to build VTK-m the
# smoke_test needs 4.5 since Kokkos is built agains rocm 4.5
LD_LIBRARY_PATH: "/opt/rocm-4.5.0/lib:${LD_LIBRARY_PATH}"
LIBRARY_PATH: "/opt/rocm-4.5.0/lib:${LIBRARY_PATH}"
KOKKOS_OPTS: >-
-DCMAKE_INSTALL_PREFIX:PATH=$CI_BUILDS_DIR/kokkos_install
-DCMAKE_CXX_COMPILER:FILEPATH=/opt/rocm-4.5.0/hip/bin/hipcc
-DKokkos_ARCH_VEGA90A:BOOL=ON
# While Kokkos and VTK-m uses ROCm 4.5.0 runtime/sdk, we need to build
# VTK-m with HIPCC from ROCM 5
CMAKE_HIP_COMPILER: "/opt/rocm-default/llvm/bin/clang++"
Kokkos_CXX_COMPILER: "/opt/rocm-default/llvm/bin/clang++"
CMAKE_HIP_ARCHITECTURES: "gfx908"
CC: gcc
CXX: g++
# DefApps/default;craype;rocm;gcc should be loaded first
JOB_MODULES: >-
DefApps/default
craype-accel-amd-gfx90a
rocm/5
rocm/4.5.0
gcc/10
cmake/3.22
git
git-lfs
kokkos/3.5.00
lsf-tools
ninja
spectrum-mpi
zstd
VTKM_SETTINGS: kokkos+hip+spock+ccache+no_rendering
VTKM_SETTINGS: kokkos+hip+gfx90a+crusher+ccache+no_rendering
interruptible: true
.setup_env_ecpci: &setup_env_ecpci |
@ -49,12 +39,12 @@
module list
export PATH="${CCACHE_INSTALL_DIR}/ccache:$PATH"
build:spock_gcc_hip:
build:crusher_gcc_hip:
stage: build
tags: [spock, shell]
tags: [crusher, shell]
extends:
- .spock_gcc_hip
- .run_spock_ci
- .crusher_gcc_hip
- .run_crusher_ci
before_script:
- *setup_env_ecpci
- mkdir -p "$CCACHE_INSTALL_DIR"
@ -62,6 +52,7 @@ build:spock_gcc_hip:
- cmake -VV -P .gitlab/ci/config/ccache.cmake
- ccache -z
- ccache -s
- .gitlab/ci/config/kokkos.sh "$CI_BUILDS_DIR" "3.7.01" $KOKKOS_OPTS
- git remote add lfs https://gitlab.kitware.com/vtk/vtk-m.git
- git fetch lfs
@ -77,18 +68,18 @@ build:spock_gcc_hip:
- build/
- .gitlab/ccache/ccache
test:spock_gcc_hip:
test:crusher_gcc_hip:
stage: test
tags: [spock, slurm]
tags: [crusher, slurm]
extends:
- .spock_gcc_hip
- .run_spock_ci
- .crusher_gcc_hip
- .run_crusher_ci
needs:
- build:spock_gcc_hip
- build:crusher_gcc_hip
dependencies:
- build:spock_gcc_hip
- build:crusher_gcc_hip
variables:
SCHEDULER_PARAMETERS: "-ACSC331 -pecp -t120 --nice=0 -c32 --gpus=4 -N 1"
SCHEDULER_PARAMETERS: "-ACSC331 -pbatch -t120 --nice=0 -c32 --gpus=4 -N 1"
# We need this to skip ctest_submit from being run inside a jsrun job
GITLAB_CI_EMULATION: 1
# Tests errors to address due to different env in Spock

@ -14,6 +14,7 @@ RUN apt update && \
ninja-build \
rsync \
ssh \
rocthrust-dev \
&& \
apt clean

@ -62,7 +62,6 @@ test:ubuntu2004_kokkos:
build:ubuntu2004_hip_kokkos:
tags:
- build
- vtkm
- docker
- linux-x86_64
@ -93,7 +92,6 @@ build:ubuntu2004_hip_kokkos:
test:ubuntu2004_hip_kokkos:
tags:
- build
- vtkm
- docker
- linux-x86_64

@ -357,6 +357,14 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm_kokkos)
add_library(vtkm_kokkos_hip INTERFACE)
set_property(TARGET vtkm_kokkos_hip PROPERTY EXPORT_NAME kokkos_hip)
install(TARGETS vtkm_kokkos_hip EXPORT ${VTKm_EXPORT_NAME})
# Make sure rocthrust is available if requested
if(VTKm_ENABLE_KOKKOS_THRUST)
find_package(rocthrust)
if(NOT rocthrust_FOUND)
message(FATAL_ERROR "rocthrust not found. Please set VTKm_ENABLE_KOKKOS_THRUST to OFF.")
endif()
endif()
endif()
add_library(vtkm_kokkos INTERFACE IMPORTED GLOBAL)

@ -227,6 +227,11 @@ include(VTKmBuildType)
# Include the vtk-m wrappers
include(VTKmWrappers)
# By default: Set VTKm_ENABLE_KOKKOS_THRUST to ON if VTKm_ENABLE_KOKKOS is ON, otherwise
# disable it (or if the user explicitly turns this option OFF)
cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)"
ON "VTKm_ENABLE_KOKKOS;Kokkos_ENABLE_CUDA OR Kokkos_ENABLE_HIP" OFF)
# Create vtkm_compiler_flags library. This is an interface library that
# holds all the C++ compiler flags that are needed for consumers and
# when building VTK-m.

@ -1,7 +1,7 @@
VTKm License Version 2.0
========================================================================
Copyright (c) 2014-2022
Copyright (c) 2014-2023
Kitware Inc.,
National Technology & Engineering Solutions of Sandia, LLC (NTESS),
UT-Battelle, LLC.,

@ -1,3 +1,6 @@
![GitLab tag](https://img.shields.io/gitlab/v/tag/vtk/vtk-m?color=red&gitlab_url=https%3A%2F%2Fgitlab.kitware.com&include_prereleases&sort=semver)
![Spack version](https://img.shields.io/spack/v/vtk-m.svg)
# VTK-m #
VTK-m is a toolkit of scientific visualization algorithms for emerging
@ -64,7 +67,7 @@ effort.
VTK-m Requires:
+ C++11 Compiler. VTK-m has been confirmed to work with the following
+ C++14 Compiler. VTK-m has been confirmed to work with the following
+ GCC 5.4+
+ Clang 5.0+
+ XCode 5.0+

@ -708,29 +708,6 @@ public:
}
};
// Get the number of components in a UnknownArrayHandle, ArrayHandle, or Field's
// ValueType.
struct NumberOfComponents
{
vtkm::IdComponent NumComponents;
template <typename ArrayHandleT>
VTKM_CONT void operator()(const ArrayHandleT&)
{
using ValueType = typename ArrayHandleT::ValueType;
using Traits = vtkm::VecTraits<ValueType>;
this->NumComponents = Traits::NUM_COMPONENTS;
}
template <typename DynamicType>
VTKM_CONT static vtkm::IdComponent Check(const DynamicType& obj)
{
NumberOfComponents functor;
vtkm::cont::CastAndCall(obj, functor);
return functor.NumComponents;
}
};
void FindFields()
{
if (PointScalarsName.empty())
@ -739,7 +716,7 @@ void FindFields()
{
auto field = GetInputDataSet().GetField(i);
if (field.GetAssociation() == vtkm::cont::Field::Association::Points &&
NumberOfComponents::Check(field) == 1)
field.GetData().GetNumberOfComponentsFlat() == 1)
{
PointScalarsName = field.GetName();
std::cerr << "[FindFields] Found PointScalars: " << PointScalarsName << "\n";
@ -754,7 +731,7 @@ void FindFields()
{
auto field = GetInputDataSet().GetField(i);
if (field.GetAssociation() == vtkm::cont::Field::Association::Cells &&
NumberOfComponents::Check(field) == 1)
field.GetData().GetNumberOfComponentsFlat() == 1)
{
CellScalarsName = field.GetName();
std::cerr << "[FindFields] CellScalars: " << CellScalarsName << "\n";
@ -769,7 +746,7 @@ void FindFields()
{
auto field = GetInputDataSet().GetField(i);
if (field.GetAssociation() == vtkm::cont::Field::Association::Points &&
NumberOfComponents::Check(field) == 3)
field.GetData().GetNumberOfComponentsFlat() == 3)
{
PointVectorsName = field.GetName();
std::cerr << "[FindFields] Found PointVectors: " << PointVectorsName << "\n";

@ -982,6 +982,55 @@ void ParseBenchmarkOptions(int& argc, char** argv)
std::cerr << "Using data set dimensions = " << DataSetDim << std::endl;
std::cerr << "Using image size = " << ImageSize << "x" << ImageSize << std::endl;
// Now go back through the arg list and remove anything that is not in the list of
// unknown options or non-option arguments.
int destArg = 1;
// This is copy/pasted from vtkm::cont::Initialize(), should probably be abstracted eventually:
for (int srcArg = 1; srcArg < argc; ++srcArg)
{
std::string thisArg{ argv[srcArg] };
bool copyArg = false;
// Special case: "--" gets removed by optionparser but should be passed.
if (thisArg == "--")
{
copyArg = true;
}
for (const option::Option* opt = options[UNKNOWN]; !copyArg && opt != nullptr;
opt = opt->next())
{
if (thisArg == opt->name)
{
copyArg = true;
}
if ((opt->arg != nullptr) && (thisArg == opt->arg))
{
copyArg = true;
}
// Special case: optionparser sometimes removes a single "-" from an option
if (thisArg.substr(1) == opt->name)
{
copyArg = true;
}
}
for (int nonOpt = 0; !copyArg && nonOpt < commandLineParse.nonOptionsCount(); ++nonOpt)
{
if (thisArg == commandLineParse.nonOption(nonOpt))
{
copyArg = true;
}
}
if (copyArg)
{
if (destArg != srcArg)
{
argv[destArg] = argv[srcArg];
}
++destArg;
}
}
argc = destArg;
}
// Adding a const char* or std::string to a vector of char* is harder than it sounds.

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a24175a16a60f3e917170907546a52de15e703bd06017fecd9c6238db9d2726
size 103177
oid sha256:3f9bdb6825e859500308217228970c406b8f75c0ab16d0c2c8d704dfa9ae2e10
size 116102

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:29d6de0eb33dfb792405d3903b1ede382cac417c29bb5d7e17e60be384db42cc
size 1940269

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7a569aff0c6872611ef75a4dcb597e1320cb966b80f840a0dbd76a29b2760dbb
size 50335052
oid sha256:347b03839fde1734ce4bd7bbf660524d039246ca3a7fd54c356a5fd7d1ffccf8
size 50335089

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:671345bdb045aeadc8e9fa1060de51e53286c74929c6c8c60a529b318f02bbfc
size 3795
oid sha256:9ab17ce444d6df1ab28f24ea997adaf2a406ca6b5035da6b17867f742380fbf4
size 3832

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ef3dfd79f0c8d18780d0749014d71c0226134041283d33de0bcd994e343dd421
size 2001070

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2bb3d36ea5ecef5e7ef1057d0dddebbc590424915083091ead3dac2928000524
size 2904465

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bffad7dae3dd6ef018ad7a9e109464ced0f3b9bc15cf1fb5d555f6d0d00b621f
size 3001624

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2cbdf56fd5445ddc5b6bc05507b8825fb8d74fe1ccce894bde03e5ff2ecf5fb6
size 525141

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b947d66dbae99a1ebb392b200a9ea0d380cfccb7fcb3a3739615d0dde558d2f1
size 238166

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8c23821f7436bce6d71593698e3cb0047752b4dd671513f8c4e961d4489f199f
size 12110311

3
data/data/third_party/README.md vendored Normal file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:362e59e70e65fd365bc64221decdea1096ac9fe4346e23126ec2d35836215832
size 456

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6f5e6e3dc559fefc7990daaec071fcd620f620e5ab8652dddaa6b43ca4ba08e7
size 222

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:55f8b9b11031d8a200145763989dedb787efee60b24f39e0c20b139899570d96
size 2197

3
data/data/third_party/visit/README.md vendored Normal file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:279231652c3bc23c31a8c7a6bf2e71f56afd11b6e09b5c05dca5dc48380ee0fb
size 1934

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ce56bb831ac66983f9689c2a73ec0dd7a7a91294f822ad19bf1caa093a8fba25
size 11295710

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:724a6dce8f6f5d6478891a915c76c57c5881467240bb055c6001725631f7833a
size 350

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2071da4365341303e401d20dc6e8bb35ebeccc24b801cc81ab87e75e3a4ef654
size 339

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:13241631e0d65d17d7bad2be44b52c0352797135fb585647f5c821e439ff9817
size 862894

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:62accba30cde47cac6980dbec18c6edc08e48f353da8f0817a810e66631cb89e
size 38

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d68d7acc1199af1de37ff581c6e39309e99dc0bae977fc9a0abf054d80aeb52a
size 2004559
oid sha256:553468d1130df26b48823fa5dc0f58196920056106b9bf0d312d651c66e423c5
size 2004653

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9a178b29073f2aa0d15375b07d0bdd28369422a352b5dcb5155cf67aebe54bbc
size 286099

@ -181,7 +181,7 @@ for (auto v : vector)
avoided in class, method, and function scopes (fully qualified
namespace references are preferred).
+ All code must be valid by the C++11 specifications. It must also
+ All code must be valid by the C++14 specifications. It must also
compile with Microsoft Visual Studio 2015.
+ New code must include regression tests that will run on the dashboards.

@ -40,6 +40,8 @@ $endif\
## Create update branch
- [ ] Freeze the release branch (In Gitlab VTK-m page)
- Settings/Repository/Protected Branches: Release; "allowed to push:No one"
- [ ] Create update branch `git checkout -b update-to-$(VERSION)`
$if(PATCH == 0 and RC == "-rc1")\
- [ ] Bring as a second parent the history of master (Solve conflicts always
@ -104,6 +106,8 @@ $endif\
- [ ] `Do: merge`
- Push tags
- [ ] `git push origin v$(VERSION)$(RC)`
- [ ] Unfreeze the release branch (In Gitlab VTK-m page)
- Settings/Repository/Protected Branches: Release; "allowed to push: Maintainers"
## Update Spack
- [ ] Update Spack package: https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/vtk-m/package.py

@ -1,13 +1,13 @@
# Minor Release Roadmap
# Release Roadmap
| Version | Date | Delay (days) | Life-cycle (*planned) | End of Support |
| --------- | ------------ | ------- | ----------- | ---------------- |
| 1.7.0 | 2021-12-01 | +8 | Long Term | 2022-12-01 |
| 1.8.0 | 2022-06-01 | +14 | Long Term | 2023-06-01 |
| 1.9.0 | 2022-09-01 | +41 | Short Term | next release |
| 2.0.0 | 2022-12-01 | | Long Term* | TBD |
| 2.1.0 | 2023-03-01 | | Short Term* | TBD |
| 2.2.0 | 2023-06-01 | | Long Term* | TBD |
| 1.9.0 | 2022-09-01 | +41 | Short Term | 2023-06-01 |
| 2.0.0 | 2022-12-01 | +52 | Long Term* | 2023-12-01 |
| 2.1.0 | 2023-06-01 | | Short Term* | TBD |
| 2.2.0 | 2023-09-01 | | Long Term* | TBD |
## Legend

@ -21,10 +21,13 @@ VTK-m 2.0 Release Notes
- Attach compressed ZFP data as WholeDataSet field
4. [Execution Environment](#Execution-Environment)
- Removed ExecutionWholeArray class
- Add initial support for aborting execution
5. [Worklets and Filters](#Worklets-and-Filters)
- Correct particle density filter output field
- Rename NewFilter base classes to Filter
- Fix handling of cell fields in Tube filter
- Fix setting fields to pass in Filter when setting mode
- Respect Filter::PassCoordinateSystem flag in filters creating coordinate systems.
6. [Build](#Build)
- More performance test options
- Output complete list of libraries for external Makefiles
@ -32,6 +35,7 @@ VTK-m 2.0 Release Notes
7. [Other](#Other)
- Expose the Variant helper class
- Fix VTKM_LOG_SCOPE
- Clarify field index ordering in Doxygen
# Core
@ -240,6 +244,29 @@ that `ExecutionWholeArray` had was that it provided an subscript operator
(somewhat incorrectly). Thus, any use of '[..]' to index the array portal
have to be changed to use the `Get` method.
## Add initial support for aborting execution
VTK-m now has preliminary support for aborting execution. The per-thread instances of
`RuntimeDeviceTracker` have a functor called `AbortChecker`. This functor can be set using
`RuntimeDeviceTracker::SetAbortChecker()` and cleared by `RuntimeDeviceTracker::ClearAbortChecker()`
The abort checker functor should return `true` if an abort is requested for the thread,
otherwise, it should return `false`.
Before launching a new task, `TaskExecute` calls the functor to see if an abort is requested,
and If so, throws an exception of type `vtkm::cont::ErrorUserAbort`.
Any code that wants to use the abort feature, should set an appropriate `AbortChecker`
functor for the target thread. Then any piece of code that has parts that can execute on
the device should be put under a `try-catch` block. Any clean-up that is required for an
aborted execution should be handled in a `catch` block that handles exceptions of type
`vtkm::cont::ErrorUserAbort`.
The limitation of this implementation is that it is control-side only. The check for abort
is done before launching a new device task. Once execution has begun on the device, there is
currently no way to abort that. Therefore, this feature is only useful for aborting code
that is made up of several smaller device task launches (Which is the case for most
worklets and filters in VTK-m)
# Worklets and Filters
## Correct particle density filter output field
@ -282,6 +309,43 @@ would also get around some problems with the implementation that was
removed here when mixing polylines with other cell types and degenerate
lines.)
## Fix setting fields to pass in `Filter` when setting mode
The `Filter` class has several version of the `SetFieldsToPass` method that
works in conjunction with the `FieldSelection` object to specify which
fields are mapped. For example, the user might have code like this to pass
all fields except those named `pointvar` and `cellvar`:
``` cpp
filter.SetFieldsToPass({ "pointvar", "cellvar" },
vtkm::filter::FieldSelection::Mode::Exclude);
```
This previously worked by implicitly creating a `FieldSelection` object
using the `std::initializer_list` filled with the 2 strings. This would
then be passed to the `SetFieldsToPass` method, which would capture the
`FieldSelection` object and change the mode.
This stopped working in a recent change to `FieldSelection` where each
entry is given its own mode. With this new class, the `FieldSelection`
constructor would capture each field in the default mode (`Select`) and
then change the default mode to `Exclude`. However, the already set modes
kept their `Select` status, which is not what is intended.
This behavior is fixed by adding `SetFieldToPass` overloads that capture
both the `initializer_list` and the `Mode` and then constructs the
`FieldSelection` correctly.
## Respect `Filter::PassCoordinateSystem` flag in filters creating coordinate systems
The `Filter` class has a `PassCoordinateSystem` flag that specifies whether
coordinate systems should be passed regardless of whether the associated
field is passed. However, if a filter created its output with the
`CreateResultCoordinateSystem` method this flag was ignored, and the
provided coordinate system was always passed. This might not be what the
user intended, so this method has been fixed to first check the
`PassCoordinateSystem` flag before setting the coordinates on the output.
# Build
## More performance test options
@ -375,3 +439,14 @@ This was not what was happening. The second log message was being printed
immediately after the first. This is because the scope was taken inside of
the `LogScope` method. The macro has been rewritten to put the tracking in
the right scope.
## Clarify field index ordering in Doxygen
The fields in a `DataSet` are indexed from `0` to `GetNumberOfFields() - 1`.
It is natural to assume that the fields will be indexed in the order that
they are added, but they are not. Rather, the indexing is arbitrary and can
change any time a field is added to the dataset.
To make this more clear, Doxygen documentation is added to the `DataSet`
methods to inform users to not make any assumptions about the order of
field indexing.

@ -0,0 +1,3 @@
# New Shrink filter
The Shrink filter shrinks the cells of a DataSet towards their centroid, computed as the average position of the cell points. This filter disconnects the cells, duplicating the points connected to multiple cells. The resulting CellSet is always an `ExplicitCellSet`.

@ -0,0 +1,18 @@
# Fast paths for `ArrayRangeCompute` fixed
The precompiled `ArrayRangeCompute` function was not following proper fast
paths for special arrays. For example, when computing the range of an
`ArrayHandleUniformPointCoordinates`, the ranges should be taken from the
origin and spacing of the special array. However, the precompiled version
was calling the generic range computation, which was doing an unnecessary
reduction over the entire array. These fast paths have been fixed.
These mistakes in the code were caused by quirks in how templated method
overloading works. To prevent this mistake from happening again in the
precompiled `ArrayRangeCompute` function and elsewhere, all templated forms
of `ArrayRangeCompute` have been deprecated. Most will call
`ArrayRangeCompute` with no issues. For those that need the templated
version, `ArrayRangeComputeTemplate` replaces the old templated
`ArrayRangeCompute`. There is exactly one templated declaration of
`ArrayRangeComputeTemplate` that uses a class, `ArrayRangeComputeImpl`,
with partial specialization to ensure the correct form is used.

@ -0,0 +1,44 @@
# Clarified license of test data
The VTK-m source comes distributed with several data files used for
regression testing. Some of these are generated specifically by VTK-m
developers and are released as part of the VTK-m license, but some come
from external sources. For those that come from external sources, we have
clarified the license and attribution of those files. In particular, the
following files originate from external sources.
* **internet.egr**: Distributed as part of a graph data set paper. The
license of this data is compatible with VTK-m's license. The file is
placed in the third-party data directory and the information has been
updated to clearly document the correct license for this data.
* **example.vtk** and **example_temp.bov**: Distributed as part of the
VisIt tutorials. This data is provided under the VisIt license (per Eric
Brugger), which is compatible with VTK-m's license. The files are moved
to the third-party data directory and the license and attribution is
clarified. (These files were previously named "noise" but were changed to
match the VisIt tutorial files they came from.)
* **vanc.vtk** Data derived from a digital elevation map of Vancouver that
comes from GTOPO30. This data is in the public domain, so it is valid for
us to use, modify, and redistribute the data under our license.
The fishtank and fusion/magField datasets were removed. These are standard
flow testing data sets that are commonly distributed. However, we could not
track down the original source and license, so to be cautious these data
sets have been removed and replaced with some generated in house.
For some of the other data sets, we have traced down the original author
and verified that they propery contribute the data to VTK-m and agree to
allow it to be distributed under VTK-m's license. Not counting the most
trivial examples, here are the originators of the non-trivial data
examples.
* **5x6_&_MC*.ctm** and **8x9test_HierarchicalAugmentedTree*.dat**: Hamish
Carr
* **warpXfields.vtk** and **warpXparticles.vtk**: Axel Huebl
* **amr_wind_flowfield.vtk**: James Kress
* **DoubleGyre*.vtk**: James Kress
* **venn250.vtk**: Abhishek Yenpure
* **wedge_cells.vtk**: Chris Laganella
* **kitchen.vtk**: Copyright owned by Kitware, Inc. (who shares the
copyright of VTK-m)

@ -1,10 +0,0 @@
# Clarify field index ordering in Doxygen
The fields in a `DataSet` are indexed from `0` to `GetNumberOfFields() - 1`.
It is natural to assume that the fields will be indexed in the order that
they are added, but they are not. Rather, the indexing is arbitrary and can
change any time a field is added to the dataset.
To make this more clear, Doxygen documentation is added to the `DataSet`
methods to inform users to not make any assumptions about the order of
field indexing.

@ -0,0 +1,23 @@
# Added `ArrayHandleRuntimeVec` to specify vector sizes at runtime.
The new `ArrayHandleRuntimeVec` is a fancy `ArrayHandle` allows you to
specify a basic array of `Vec`s where the number of components of the `Vec`
are not known until runtime. (It can also optionally specify scalars.) The
behavior is much like that of `ArrayHandleGroupVecVariable` except that its
representation is much more constrained. This constrained representation
allows it to be automatically converted to an `ArrayHandleBasic` with the
proper `Vec` value type. This allows one part of code (such as a file
reader) to create an array with any `Vec` size, and then that array can be
fed to an algorithm that expects an `ArrayHandleBasic` of a certain value
type.
The `UnknownArrayHandle` has also been updated to allow
`ArrayHandleRuntimeVec` to work interchangeably with basic `ArrayHandle`.
If an `ArrayHandleRuntimeVec` is put into an `UnknownArrayHandle`, it can
be later retrieved as an `ArrayHandleBasic` as long as the base component
type matches and it has the correct amount of components. This means that
an array can be created as an `ArrayHandleRuntimeVec` and be used with any
filters or most other features designed to operate on basic `ArrayHandle`s.
Likewise, an array added as a basic `ArrayHandle` can be retrieved in an
`ArrayHandleRuntimeVec`. This makes it easier to pull arrays from VTK-m and
place them in external structures (such as `vtkDataArray`).

@ -0,0 +1,22 @@
# Simplified serialization of DataSet objects
`vtkm::cont::DataSet` is a dynamic object that can hold cell sets and
fields of many different types, none of which are known until runtime. This
causes a problem with serialization, which has to know what type to compile
the serialization for, particularly when unserializing the type at the
receiving end. The original implementation "solved" the problem by creating
a secondary wrapper object that was templated on types of field arrays and
cell sets that might be serialized. This is not a great solution as it
punts the problem to algorithm developers.
This problem has been completely solved for fields, as it is possible to
serialize most types of arrays without knowing their type now. You still
need to iterate over every possible `CellSet` type, but there are not that
many `CellSet`s that are practically encountered. Thus, there is now a
direct implementation of `Serialization` for `DataSet` that covers all the
data types you are likely to encounter.
The old `SerializableDataSet` has been deprecated. In the unlikely event an
algorithm needs to transfer a non-standard type of `CellSet` (such as a
permuted cell set), it can use the replacement `DataSetWithCellSetTypes`,
which just specifies the cell set types.

@ -1,3 +1,4 @@
# New Statistics filter
The statistics filter computes the descriptive statistics of the fields specified by users based on `DescriptiveStatistics`. Users can set `RequiredStatsList` to specify which statistics will be stored in the output data set.
The statistics filter computes the descriptive statistics of the fields specified by users based on `DescriptiveStatistics`. Users can set `RequiredStatsList` to specify which statistics will be stored in the output data set. The statistics filter supports the distributed memory case based on the vtkmdiy, and the process with rank 0 will return the correct final reduced results.

@ -0,0 +1,18 @@
# Added support for getting vec sizes of unknown arrays when runtime selected
The `GetNumberOfComponents` and `GetNumberOfComponentsFlat` methods in
`UnknownArrayHandle` have been updated to correctly report the number of
components in special `ArrayHandle`s where the `Vec` sizes of the values
are not selected until runtime.
Previously, these methods always reported 0 because the value type could
not report the size of the `Vec`. The lookup has been modified to query the
`ArrayHandle`'s `Storage` for the number of components where supported.
Note that this only works on `Storage` that provides a method to get the
runtime `Vec` size. If that is not provided, as will be the case if the
number of components can vary from one value to the next, it will still
report 0.
This feature is implemented by looking for a method named
`GetNumberOfComponents` is the `Storage` class for the `ArrayHandle`. If
this method is found, it is used to query the size at runtime.

@ -0,0 +1,19 @@
# Implemented `VecTraits` class for all types
The `VecTraits` class allows templated functions, methods, and classes to
treat type arguments uniformly as `Vec` types or to otherwise differentiate
between scalar and vector types. This only works for types that `VecTraits`
is defined for.
The `VecTraits` templated class now has a default implementation that will
be used for any type that does not have a `VecTraits` specialization. This
removes many surprise compiler errors when using a template that, unknown
to you, has `VecTraits` in its implementation.
One potential issue is that if `VecTraits` gets defined for a new type, the
behavior of `VecTraits` could change for that type in backward-incompatible
ways. If `VecTraits` is used in a purely generic way, this should not be an
issue. However, if assumptions were made about the components and length,
this could cause problems.
Fixes #589.

@ -0,0 +1,3 @@
# Added a reader for VisIt files.
A VisIt file is a text file that contains the path and filename of a number of VTK files. This provides a convenient way to load `vtkm::cont::PartitionedDataSet` data from VTK files. The first line of the file is the keyword `!NBLOCKS <N>` that specifies the number of VTK files to be read.

@ -24,9 +24,9 @@ int main(int argc, char* argv[])
if ((argc < 4) || (argc > 5))
{
std::cerr << "Usage: " << argv[0] << " in_data.vtk field_name clip_value [out_data.vtk]\n\n";
std::cerr << "For example, you could use the ucd3d.vtk that comes with the VTK-m source:\n\n";
std::cerr << "For example, you could use the example.vtk that comes with the VTK-m source:\n\n";
std::cerr << " " << argv[0]
<< " <path-to-vtkm-source>/data/data/unstructured/ucd3d.vtk v 0.3\n";
<< " <path-to-vtkm-source>/data/data/third_party/visit/example.vtk temp 3.5\n";
return 1;
}
std::string infilename = argv[1];

@ -16,11 +16,11 @@
#include <vtkm/io/VTKDataSetWriter.h>
// Example computing streamlines.
// An example vector field is available in the vtk-m data directory: magField.vtk
// An example vector field is available in the vtk-m data directory: rotate-vectors.vtk
// Example usage:
// this will advect 200 particles 50 steps using a step size of 0.01
// this will advect 200 particles 50 steps using a step size of 0.05
//
// Particle_Advection <path-to-data-dir>/magField.vtk vec 200 50 0.01 output.vtk
// Particle_Advection <path-to-data-dir>/rotate-vectors.vtk rotate 200 50 0.05 output.vtk
//
int main(int argc, char** argv)
@ -28,10 +28,10 @@ int main(int argc, char** argv)
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
auto config = vtkm::cont::Initialize(argc, argv, opts);
if (argc < 8)
if (argc < 7)
{
std::cerr << "Usage: " << argv[0]
<< "dataFile varName numSeeds numSteps stepSize outputFile [options]" << std::endl;
<< " dataFile varName numSeeds numSteps stepSize outputFile [options]" << std::endl;
std::cerr << "where options are: " << std::endl << config.Usage << std::endl;
return -1;
}

@ -133,8 +133,7 @@ public:
this->Decomposer.fill_bounds(bds, target.gid);
auto extractedDS = this->Extract(*block, bds);
// TODO: Need a better way to serialize DataSet. See issue #725.
rp.enqueue(target, vtkm::cont::SerializableDataSet<>(extractedDS));
rp.enqueue(target, extractedDS);
}
// clear our dataset.
*block = vtkm::cont::DataSet();
@ -149,10 +148,9 @@ public:
auto target = rp.in_link().target(cc);
if (rp.incoming(target.gid).size() > 0)
{
// TODO: Need a better way to serialize DataSet. See issue #725.
vtkm::cont::SerializableDataSet<> sds;
rp.dequeue(target.gid, sds);
receives.push_back(sds.DataSet);
vtkm::cont::DataSet incomingDS;
rp.dequeue(target.gid, incomingDS);
receives.push_back(incomingDS);
numValues += receives.back().GetCoordinateSystem(0).GetNumberOfPoints();
}
}

@ -75,11 +75,11 @@ void LoadData(std::string& fname, std::vector<vtkm::cont::DataSet>& dataSets, in
}
// Example computing streamlines.
// An example vector field is available in the vtk-m data directory: magField.vtk
// An example vector field is available in the vtk-m data directory: rotate-vectors.vtk
// Example usage:
// this will advect 200 particles 50 steps using a step size of 0.01
// this will advect 200 particles 50 steps using a step size of 0.05
//
// Particle_Advection <path-to-data-dir>/magField.vtk vec 200 50 0.01 output.vtk
// Particle_Advection <path-to-data-dir>/rotate-vectors.vtk vec 200 50 0.05 output.vtk
//
int main(int argc, char** argv)

@ -24,8 +24,9 @@ int main(int argc, char* argv[])
if ((argc < 2) || (argc > 3))
{
std::cerr << "Usage: " << argv[0] << " in_data.vtk [out_data.vtk]\n\n";
std::cerr << "For example, you could use the ucd3d.vtk that comes with the VTK-m source:\n\n";
std::cerr << " " << argv[0] << " <path-to-vtkm-source>/data/data/unstructured/ucd3d.vtk\n";
std::cerr << "For example, you could use the example.vtk that comes with the VTK-m source:\n\n";
std::cerr << " " << argv[0]
<< " <path-to-vtkm-source>/data/data/third_party/visit/example.vtk\n";
return 1;
}
std::string infilename = argv[1];

@ -9,11 +9,10 @@
##============================================================================
#add the directory that contains the VTK-m config file to the cmake
#path so that our examples can find VTK-m
#path so that our tutorial can find VTK-m
#Normally when running CMake, you need to set the VTKm_DIR to
#find the VTKmConfig.cmake file. Because we already know where this
#file is, we can add the location to look to CMAKE_PREFIX_PATH.
set(CMAKE_PREFIX_PATH ${VTKm_BINARY_DIR}/${VTKm_INSTALL_CONFIG_DIR})
cmake_minimum_required(VERSION 3.12...3.15 FATAL_ERROR)
@ -22,20 +21,41 @@ project(VTKm_tut)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_TUTORIALS)
# VTK-m tutorial targets expect vtkm libraries to be namespaced with the prefix vtkm::.
# However, as the tutorial can also be built as part of the VTK-m code,
# those prefix are not added to the targets (This happens during the
# installation). To workaround this issue here, we create IMPORTED libs linking
# to the vtkm libraries used by the tutorial targets with the expected vtkm:: prefix.
vtkm_module_get_list(module_list)
foreach(tgt IN LISTS module_list)
if(TARGET ${tgt})
# The reason of creating this phony IMPORTED libraries instead of making
# ALIAS libraries is that ALIAS libraries are GLOBAL whereas IMPORTED are
# local at the directory level where they are created. We do not want these
# phony targets to be visible outside of the tutorial directory.
vtkm_target_mangle(tgt_name_mangled ${tgt})
add_library("vtkm::${tgt_name_mangled}" INTERFACE IMPORTED)
target_link_libraries("vtkm::${tgt_name_mangled}" INTERFACE ${tgt})
endif()
endforeach()
endif()
add_executable(io io.cxx)
target_link_libraries(io vtkm_filter vtkm_io)
target_link_libraries(io vtkm::io)
add_executable(contour contour.cxx)
target_link_libraries(contour vtkm_filter vtkm_io)
target_link_libraries(contour vtkm::filter_core vtkm::filter_contour vtkm::io)
add_executable(contour_two_fields contour_two_fields.cxx)
target_link_libraries(contour_two_fields vtkm_filter vtkm_io)
target_link_libraries(contour_two_fields vtkm::filter_core vtkm::filter_contour vtkm::io)
add_executable(two_filters two_filters.cxx)
target_link_libraries(two_filters vtkm_filter vtkm_io)
target_link_libraries(two_filters vtkm::filter_core vtkm::filter_contour vtkm::io)
add_executable(mag_grad mag_grad.cxx)
target_link_libraries(mag_grad vtkm_filter vtkm_io)
target_link_libraries(mag_grad vtkm::filter_core vtkm::filter_vector_analysis vtkm::io)
# Because mag_grad.cxx creates a worklet with code that
# runs on a GPU, it needs additional information.
vtkm_add_target_information(mag_grad
@ -44,23 +64,23 @@ vtkm_add_target_information(mag_grad
if (VTKm_ENABLE_RENDERING)
add_executable(rendering rendering.cxx)
target_link_libraries(rendering vtkm_filter vtkm_io vtkm_rendering)
target_link_libraries(rendering vtkm::io vtkm::rendering)
endif ()
add_executable(error_handling error_handling.cxx)
target_link_libraries(error_handling vtkm_filter vtkm_io)
target_link_libraries(error_handling vtkm::filter_core vtkm::filter_contour vtkm::io)
add_executable(logging logging.cxx)
target_link_libraries(logging vtkm_filter vtkm_io)
target_link_libraries(logging vtkm::io)
add_executable(point_to_cell point_to_cell.cxx)
target_link_libraries(point_to_cell vtkm_cont vtkm_filter vtkm_io)
target_link_libraries(point_to_cell vtkm::worklet vtkm::filter_core vtkm::io)
vtkm_add_target_information(point_to_cell
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES point_to_cell.cxx)
add_executable(extract_edges extract_edges.cxx)
target_link_libraries(extract_edges vtkm_cont vtkm_filter vtkm_io)
target_link_libraries(extract_edges vtkm::cont vtkm::filter_core vtkm::filter_contour vtkm::worklet vtkm::io)
vtkm_add_target_information(extract_edges
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES extract_edges.cxx)

@ -69,7 +69,7 @@ public:
/// \brief A tag to determine whether the type has multiple components.
///
/// This tag is either TypeTraitsScalarTag or TypeTraitsVectorTag. Scalars can
/// also be treated as vectors.
/// also be treated as vectors with VecTraits.
using DimensionalityTag = vtkm::TypeTraitsUnknownTag;
VTKM_EXEC_CONT static T ZeroInitialization() { return T(); }

@ -53,6 +53,18 @@ public:
}
}
template <vtkm::IdComponent N>
VTKM_EXEC_CONT operator vtkm::Vec<ComponentType, N>() const
{
vtkm::Vec<ComponentType, N> result;
this->CopyInto(result);
for (vtkm::IdComponent index = this->NumComponents; index < N; ++index)
{
result[index] = vtkm::TypeTraits<ComponentType>::ZeroInitialization();
}
return result;
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
vtkm::internal::ArrayPortalValueReference<PortalType> operator[](vtkm::IdComponent index) const
@ -61,6 +73,20 @@ public:
index + this->Offset);
}
template <typename T, vtkm::IdComponent N>
VTKM_EXEC_CONT VecFromPortal& operator=(const vtkm::Vec<T, N>& src)
{
vtkm::IdComponent numComponents = vtkm::Min(N, this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
this->Portal.Set(index + this->Offset, src[index]);
}
return *this;
}
VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; }
VTKM_EXEC_CONT vtkm::Id GetOffset() const { return this->Offset; }
private:
PortalType Portal;
vtkm::IdComponent NumComponents;
@ -109,6 +135,15 @@ struct VecTraits<vtkm::VecFromPortal<PortalType>>
return vector[componentIndex];
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
static void SetComponent(const VecType& vector,
vtkm::IdComponent componentIndex,
const ComponentType& value)
{
vector[componentIndex] = value;
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)

@ -10,6 +10,8 @@
#ifndef vtk_m_VecTraits_h
#define vtk_m_VecTraits_h
#include <vtkm/Deprecated.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/Types.h>
namespace vtkm
@ -42,60 +44,55 @@ struct VecTraitsTagSizeVariable
{
};
namespace internal
{
template <vtkm::IdComponent numComponents>
struct VecTraitsMultipleComponentChooser
{
using Type = vtkm::VecTraitsTagMultipleComponents;
};
template <>
struct VecTraitsMultipleComponentChooser<1>
{
using Type = vtkm::VecTraitsTagSingleComponent;
};
} // namespace internal
/// The VecTraits class gives several static members that define how
/// to use a given type as a vector.
/// \brief Traits that can be queried to treat any type as a `Vec`.
///
template <class VecType>
/// The VecTraits class gives several static members that define how
/// to use a given type as a vector. This is useful for templated
/// functions and methods that have a parameter that could be either
/// a standard scalar type or a `Vec` or some other `Vec`-like
/// object. When using this class, scalar objects are treated like
/// a `Vec` of size 1.
///
/// The default implementation of this template treats the type as
/// a scalar. Types that actually behave like vectors should
/// specialize this template to provide the proper information.
///
template <class T>
struct VTKM_NEVER_EXPORT VecTraits
{
#ifdef VTKM_DOXYGEN_ONLY
// The base VecTraits should not be used with qualifiers.
VTKM_STATIC_ASSERT_MSG((std::is_same<std::remove_pointer_t<std::decay_t<T>>, T>::value),
"The base VecTraits should not be used with qualifiers.");
/// \brief Type of the components in the vector.
///
/// If the type is really a scalar, then the component type is the same as the scalar type.
///
using ComponentType = typename VecType::ComponentType;
using ComponentType = T;
/// \brief Base component type in the vector.
///
/// Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it
/// returns the base scalar type at the end of the composition (T in this example).
///
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
using BaseComponentType = T;
/// \brief Number of components in the vector.
///
/// This is only defined for vectors of a static size.
///
static constexpr vtkm::IdComponent NUM_COMPONENTS = VecType::NUM_COMPONENTS;
static constexpr vtkm::IdComponent NUM_COMPONENTS = 1;
/// Number of components in the given vector.
///
static vtkm::IdComponent GetNumberOfComponents(const VecType& vec);
static constexpr vtkm::IdComponent GetNumberOfComponents(const T&) { return NUM_COMPONENTS; }
/// \brief A tag specifying whether this vector has multiple components (i.e. is a "real" vector).
///
/// This tag can be useful for creating specialized functions when a vector
/// is really just a scalar.
///
using HasMultipleComponents =
typename internal::VecTraitsMultipleComponentChooser<NUM_COMPONENTS>::Type;
using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent;
/// \brief A tag specifying whether the size of this vector is known at compile time.
///
@ -107,81 +104,113 @@ struct VTKM_NEVER_EXPORT VecTraits
/// Returns the value in a given component of the vector.
///
VTKM_EXEC_CONT static const ComponentType& GetComponent(
const typename std::remove_const<VecType>::type& vector,
vtkm::IdComponent component);
VTKM_EXEC_CONT static ComponentType& GetComponent(
typename std::remove_const<VecType>::type& vector,
vtkm::IdComponent component);
VTKM_EXEC_CONT static const ComponentType& GetComponent(const T& vector,
vtkm::IdComponent vtkmNotUsed(component))
{
return vector;
}
VTKM_EXEC_CONT static ComponentType& GetComponent(T& vector,
vtkm::IdComponent vtkmNotUsed(component))
{
return vector;
}
/// Changes the value in a given component of the vector.
///
VTKM_EXEC_CONT static void SetComponent(VecType& vector,
vtkm::IdComponent component,
ComponentType value);
VTKM_EXEC_CONT static void SetComponent(T& vector,
vtkm::IdComponent vtkmNotUsed(component),
ComponentType value)
{
vector = value;
}
/// \brief Get a vector of the same type but with a different component.
///
/// This type resolves to another vector with a different component type. For example,
/// @code vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> @endcode is vtkm::Vec<T2, N>.
/// This replacement is not recursive. So @code VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> @endcode
/// is vtkm::Vec<T2, N>.
/// `vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2>` is `vtkm::Vec<T2, N>`.
/// This replacement is not recursive. So `VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>`
/// is `vtkm::Vec<T2, N>`.
///
template <typename NewComponentType>
using ReplaceComponentType = VecTemplate<NewComponentType, N>;
using ReplaceComponentType = NewComponentType;
/// \brief Get a vector of the same type but with a different base component.
///
/// This type resolves to another vector with a different base component type. The replacement
/// is recursive for nested types. For example,
/// @code VecTraits<Vec<Vec<T, M>, N>::ReplaceBaseComponentType<T2> @endcode is Vec<Vec<T2, M>, N>.
/// `VecTraits<Vec<Vec<T, M>, N>::ReplaceBaseComponentType<T2>` is `Vec<Vec<T2, M>, N>`.
///
template <typename NewComponentType>
using ReplaceBaseComponentType = VecTemplate<
typename VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>,
N>;
using ReplaceBaseComponentType = NewComponentType;
/// Copies the components in the given vector into a given Vec object.
///
template <vktm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest);
#endif // VTKM_DOXYGEN_ONLY
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const T& src, vtkm::Vec<ComponentType, destSize>& dest)
{
dest[0] = src;
}
};
namespace detail
{
template <typename T>
struct HasVecTraitsImpl
{
template <typename A, typename S = typename vtkm::VecTraits<A>::ComponentType>
static std::true_type Test(A*);
using HasVecTraits VTKM_DEPRECATED(2.1, "All types now have VecTraits defined.") = std::true_type;
static std::false_type Test(...);
using Type = decltype(Test(std::declval<T*>()));
};
} // namespace detail
/// \brief Determines whether the given type has VecTraits defined.
///
/// If the given type T has a valid VecTraits class, then HasVecTraits<T> will be set to
/// std::true_type. Otherwise it will be set to std::false_type. For example,
/// HasVecTraits<vtkm::Id> is the same as std::true_type whereas HasVecTraits<void *> is the same
/// as std::false_type. This is useful to block the definition of methods using VecTraits when
/// VecTraits are not defined.
///
template <typename T>
using HasVecTraits = typename detail::HasVecTraitsImpl<T>::Type;
// This partial specialization allows you to define a non-const version of
// VecTraits and have it still work for const version.
//
// These partial specializations allow VecTraits to work with const and reference qualifiers.
template <typename T>
struct VTKM_NEVER_EXPORT VecTraits<const T> : VecTraits<T>
{
};
template <typename T>
struct VTKM_NEVER_EXPORT VecTraits<T&> : VecTraits<T>
{
};
template <typename T>
struct VTKM_NEVER_EXPORT VecTraits<const T&> : VecTraits<T>
{
};
// This partial specialization allows VecTraits to work with pointers.
template <typename T>
struct VTKM_NEVER_EXPORT VecTraits<T*> : VecTraits<T>
{
VTKM_EXEC_CONT static vtkm::IdComponent GetNumberOfComponents(const T* vector)
{
return VecTraits<T>::GetNumberOfComponents(*vector);
}
VTKM_EXEC_CONT static auto GetComponent(const T* vector, vtkm::IdComponent component)
-> decltype(VecTraits<T>::GetComponent(*vector, component))
{
return VecTraits<T>::GetComponent(*vector, component);
}
VTKM_EXEC_CONT static auto GetComponent(T* vector, vtkm::IdComponent component)
-> decltype(VecTraits<T>::GetComponent(*vector, component))
{
return VecTraits<T>::GetComponent(*vector, component);
}
VTKM_EXEC_CONT static void SetComponent(T* vector,
vtkm::IdComponent component,
typename VecTraits<T>::ComponentType value)
{
VecTraits<T>::SetComponent(*vector, component, value);
}
template <typename NewComponentType>
using ReplaceComponentType =
typename VecTraits<T>::template ReplaceComponentType<NewComponentType>*;
template <typename NewComponentType>
using ReplaceBaseComponentType =
typename VecTraits<T>::template ReplaceBaseComponentType<NewComponentType>*;
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(
const T* src,
vtkm::Vec<typename VecTraits<T>::ComponentType, destSize>& dest)
{
VecTraits<T>::CopyInto(*src, dest);
}
};
template <typename T>
struct VTKM_NEVER_EXPORT VecTraits<const T*> : VecTraits<T*>
{
};
#if defined(VTKM_GCC) && (__GNUC__ <= 5)
namespace detail
@ -203,6 +232,23 @@ struct VecReplaceBaseComponentTypeGCC4or5
} // namespace detail
#endif // GCC Version 4.8
namespace internal
{
template <vtkm::IdComponent numComponents, typename ComponentType>
struct VecTraitsMultipleComponentChooser
{
using Type = vtkm::VecTraitsTagMultipleComponents;
};
template <typename ComponentType>
struct VecTraitsMultipleComponentChooser<1, ComponentType>
{
using Type = typename vtkm::VecTraits<ComponentType>::HasMultipleComponents;
};
} // namespace internal
template <typename T, vtkm::IdComponent Size>
struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
{
@ -235,7 +281,7 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
/// when a vector is really just a scalar.
///
using HasMultipleComponents =
typename internal::VecTraitsMultipleComponentChooser<NUM_COMPONENTS>::Type;
typename internal::VecTraitsMultipleComponentChooser<NUM_COMPONENTS, ComponentType>::Type;
/// A tag specifying whether the size of this vector is known at compile
/// time. If set to \c VecTraitsTagSizeStatic, then \c NUM_COMPONENTS is set.
@ -502,7 +548,8 @@ namespace internal
/// Used for overriding VecTraits for basic scalar types.
///
template <typename ScalarType>
struct VTKM_NEVER_EXPORT VecTraitsBasic
struct VTKM_DEPRECATED(2.1, "VecTraitsBasic is now the default implementation for VecTraits.")
VTKM_NEVER_EXPORT VecTraitsBasic
{
using ComponentType = ScalarType;
using BaseComponentType = ScalarType;
@ -541,87 +588,41 @@ struct VTKM_NEVER_EXPORT VecTraitsBasic
}
};
namespace detail
{
template <typename T, typename = vtkm::HasVecTraits<T>>
struct VTKM_NEVER_EXPORT SafeVecTraitsImpl;
template <typename T>
struct VTKM_NEVER_EXPORT SafeVecTraitsImpl<T, std::true_type> : vtkm::VecTraits<T>
{
};
template <typename T>
struct VTKM_NEVER_EXPORT SafeVecTraitsImpl<T, std::false_type> : vtkm::internal::VecTraitsBasic<T>
{
};
} // namespace detail
/// \brief A version of VecTraits that will be available for any type.
///
/// The `VecTraits` template is only defined for types that have a specific specialization
/// for it. That means if you use `VecTraits` in a template, that template will likely
/// fail to build for types that are not defined for `VecTraits`.
///
/// To use `VecTraits` in a class that should support all types, not just those with
/// defined `VecTraits`, you can use this "safe" version. `SafeVecTraits` is the same as
/// `VecTraits` if the latter is defined. If the `VecTraits` are not defined, then
/// `SafeVecTraits` treats the type as a simple scalar value.
///
/// This template ensures that it will work reasonably well for all types. But be careful
/// as if `VecTraits` is later defined, the template is likely to change.
///
template <typename T>
struct VTKM_NEVER_EXPORT SafeVecTraits : detail::SafeVecTraitsImpl<T>
struct VTKM_DEPRECATED(2.1 "VecTraits now safe to use on any type.") VTKM_NEVER_EXPORT SafeVecTraits
: vtkm::VecTraits<T>
{
};
} // namespace internal
/// \brief VecTraits for Pair types
///
/// Although a pair would seem better as a size-2 vector, we treat it as a
/// scalar. This is because a \c Vec is assumed to have the same type for
/// every component, and a pair in general has a different type for each
/// component. Thus we treat a pair as a "scalar" unit.
///
template <typename T, typename U>
struct VTKM_NEVER_EXPORT VecTraits<vtkm::Pair<T, U>>
: public vtkm::internal::VecTraitsBasic<vtkm::Pair<T, U>>
namespace detail
{
struct VTKM_DEPRECATED(2.1,
"VTKM_BASIC_TYPE_VECTOR is no longer necessary because VecTraits implements "
"basic type by default.") VTKM_BASIC_TYPE_VECTOR_is_deprecated
{
};
template <typename T>
struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning;
}
} // namespace vtkm
#define VTKM_BASIC_TYPE_VECTOR(type) \
namespace vtkm \
{ \
template <> \
struct VTKM_NEVER_EXPORT VecTraits<type> : public vtkm::internal::VecTraitsBasic<type> \
{ \
}; \
#define VTKM_BASIC_TYPE_VECTOR(type) \
namespace vtkm \
{ \
namespace detail \
{ \
template <> \
struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning<type> \
: public vtkm::detail::VTKM_BASIC_TYPE_VECTOR_is_deprecated \
{ \
}; \
} \
}
/// Allows you to treat basic types as if they were vectors.
VTKM_BASIC_TYPE_VECTOR(float)
VTKM_BASIC_TYPE_VECTOR(double)
VTKM_BASIC_TYPE_VECTOR(bool)
VTKM_BASIC_TYPE_VECTOR(char)
VTKM_BASIC_TYPE_VECTOR(signed char)
VTKM_BASIC_TYPE_VECTOR(unsigned char)
VTKM_BASIC_TYPE_VECTOR(short)
VTKM_BASIC_TYPE_VECTOR(unsigned short)
VTKM_BASIC_TYPE_VECTOR(int)
VTKM_BASIC_TYPE_VECTOR(unsigned int)
VTKM_BASIC_TYPE_VECTOR(long)
VTKM_BASIC_TYPE_VECTOR(unsigned long)
VTKM_BASIC_TYPE_VECTOR(long long)
VTKM_BASIC_TYPE_VECTOR(unsigned long long)
//#undef VTKM_BASIC_TYPE_VECTOR
#endif //vtk_m_VecTraits_h

@ -33,21 +33,6 @@ namespace cont
namespace detail
{
// Compile-time check to make sure that an `ArrayHandle` passed to `ArrayCopy`
// can be passed to a `UnknownArrayHandle`. This function does nothing
// except provide a compile error that is easier to understand than if you
// let it go and error in `UnknownArrayHandle`. (Huh? I'm not using that.)
template <typename T>
inline void ArrayCopyValueTypeCheck()
{
VTKM_STATIC_ASSERT_MSG(vtkm::HasVecTraits<T>::value,
"An `ArrayHandle` that has a special value type that is not supported "
"by the precompiled version of `ArrayCopy` has been used. If this array "
"must be deep copied, consider using `ArrayCopyDevice`. Look at the "
"compile error for the type assigned to template parameter `T` to "
"see the offending type.");
}
template <typename S>
struct ArrayCopyConcreteSrc;
@ -74,8 +59,6 @@ void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
std::false_type,
std::true_type)
{
detail::ArrayCopyValueTypeCheck<T>();
using DestType = vtkm::cont::ArrayHandle<T, S>;
if (source.CanConvert<DestType>())
{
@ -96,9 +79,6 @@ void ArrayCopyImpl(const vtkm::cont::ArrayHandle<TS, SS>& source,
std::true_type,
std::true_type)
{
ArrayCopyValueTypeCheck<TS>();
ArrayCopyValueTypeCheck<TD>();
detail::ArrayCopyConcreteSrc<SS>{}(source, destination);
}

@ -37,7 +37,7 @@ namespace internal
// is defined rather than where it is resolved. This causes problems when extracting
// components of, say, an ArrayHandleMultiplexer holding an ArrayHandleSOA.
template <typename T, typename S>
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType>
ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy)
@ -53,7 +53,7 @@ ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle<T, S>& src,
<< vtkm::cont::TypeToString<vtkm::cont::ArrayHandle<T, S>>()
<< " requires an inefficient memory copy.");
using BaseComponentType = typename vtkm::internal::SafeVecTraits<T>::BaseComponentType;
using BaseComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
vtkm::Id numValues = src.GetNumberOfValues();
vtkm::cont::ArrayHandleBasic<BaseComponentType> dest;
dest.Allocate(numValues);
@ -78,10 +78,10 @@ template <typename S>
struct ArrayExtractComponentImpl : ArrayExtractComponentImplInefficient
{
template <typename T>
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>
operator()(const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> operator()(
const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
{
// This is the slow "default" implementation. ArrayHandle implementations should provide
// more efficient overloads where applicable.
@ -93,15 +93,13 @@ template <>
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagStride>
{
template <typename T>
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>
operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagStride>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagStride>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
{
return this->DoExtract(src,
componentIndex,
allowCopy,
typename vtkm::internal::SafeVecTraits<T>::HasMultipleComponents{});
return this->DoExtract(
src, componentIndex, allowCopy, typename vtkm::VecTraits<T>::HasMultipleComponents{});
}
private:
@ -112,7 +110,7 @@ private:
vtkm::VecTraitsTagSingleComponent) const
{
VTKM_ASSERT(componentIndex == 0);
using VTraits = vtkm::internal::SafeVecTraits<T>;
using VTraits = vtkm::VecTraits<T>;
using TBase = typename VTraits::BaseComponentType;
VTKM_STATIC_ASSERT(VTraits::NUM_COMPONENTS == 1);
@ -135,7 +133,7 @@ private:
vtkm::CopyFlag allowCopy,
vtkm::VecTraitsTagMultipleComponents) const
{
using VTraits = vtkm::internal::SafeVecTraits<VecType>;
using VTraits = vtkm::VecTraits<VecType>;
using T = typename VTraits::ComponentType;
constexpr vtkm::IdComponent N = VTraits::NUM_COMPONENTS;
@ -254,10 +252,10 @@ using ArrayExtractComponentIsInefficient = typename std::is_base_of<
/// `vtkm::cont::internal::ArrayExtractComponentImpl`.
///
template <typename T, typename S>
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>
ArrayExtractComponent(const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On)
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> ArrayExtractComponent(
const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On)
{
return internal::ArrayExtractComponentImpl<S>{}(src, componentIndex, allowCopy);
}

@ -120,9 +120,6 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle<vtkm::Id, SIds>& ids
const vtkm::cont::ArrayHandle<T, SData>& data,
vtkm::cont::ArrayHandle<T, SOut>& output)
{
VTKM_STATIC_ASSERT_MSG(
vtkm::HasVecTraits<T>::value,
"ArrayGetValues can only be used with arrays containing value types with VecTraits defined.");
using DataArrayHandle = vtkm::cont::ArrayHandle<T, SData>;
using InefficientExtract =
vtkm::cont::internal::ArrayExtractComponentIsInefficient<DataArrayHandle>;

@ -752,9 +752,9 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value(
std::ostream& out,
vtkm::VecTraitsTagMultipleComponents)
{
using Traits = vtkm::internal::SafeVecTraits<T>;
using Traits = vtkm::VecTraits<T>;
using ComponentType = typename Traits::ComponentType;
using IsVecOfVec = typename vtkm::internal::SafeVecTraits<ComponentType>::HasMultipleComponents;
using IsVecOfVec = typename vtkm::VecTraits<ComponentType>::HasMultipleComponents;
vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value);
out << "(";
printSummary_ArrayHandle_Value(Traits::GetComponent(value, 0), out, IsVecOfVec());
@ -774,10 +774,10 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value(
{
out << "{";
printSummary_ArrayHandle_Value(
value.first, out, typename vtkm::internal::SafeVecTraits<T1>::HasMultipleComponents());
value.first, out, typename vtkm::VecTraits<T1>::HasMultipleComponents());
out << ",";
printSummary_ArrayHandle_Value(
value.second, out, typename vtkm::internal::SafeVecTraits<T2>::HasMultipleComponents());
value.second, out, typename vtkm::VecTraits<T2>::HasMultipleComponents());
out << "}";
}
@ -793,7 +793,7 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle(
{
using ArrayType = vtkm::cont::ArrayHandle<T, StorageT>;
using PortalType = typename ArrayType::ReadPortalType;
using IsVec = typename vtkm::internal::SafeVecTraits<T>::HasMultipleComponents;
using IsVec = typename vtkm::VecTraits<T>::HasMultipleComponents;
vtkm::Id sz = array.GetNumberOfValues();

@ -11,6 +11,8 @@
#define vtk_m_cont_ArrayHandleCartesianProduct_h
#include <vtkm/Assert.h>
#include <vtkm/Range.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandle.h>
@ -486,6 +488,77 @@ struct ArrayExtractComponentImpl<vtkm::cont::StorageTagCartesianProduct<STs...>>
}
};
template <typename S>
struct ArrayRangeComputeImpl;
template <typename ST1, typename ST2, typename ST3>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input_,
vtkm::cont::DeviceAdapterId device) const
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
auto resultPortal = result.WritePortal();
const vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>& input = input_;
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::IdComponent index = 0;
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetFirstArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST1>{}(firstArray, device);
vtkm::Id numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
auto componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetSecondArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST2>{}(secondArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetThirdArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST3>{}(thirdArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
return result;
}
};
} // namespace internal
}

@ -12,6 +12,9 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/Range.h>
#include <vtkm/VecFlat.h>
namespace vtkm
{
namespace cont
@ -90,6 +93,36 @@ vtkm::cont::ArrayHandleConstant<T> make_ArrayHandleConstant(T value, vtkm::Id nu
{
return vtkm::cont::ArrayHandleConstant<T>(value, numberOfValues);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagConstant>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
vtkm::cont::DeviceAdapterId) const
{
auto value = vtkm::make_VecFlat(input.ReadPortal().Get(0));
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(value.GetNumberOfComponents());
auto resultPortal = result.WritePortal();
for (vtkm::IdComponent index = 0; index < value.GetNumberOfComponents(); ++index)
{
resultPortal.Set(index, vtkm::Range{ value[index], value[index] });
}
return result;
}
};
} // namespace internal
}
} // vtkm::cont

@ -12,6 +12,7 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/Range.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecTraits.h>
@ -76,27 +77,17 @@ private:
namespace detail
{
template <typename T, typename UseVecTraits = vtkm::HasVecTraits<T>>
struct CanCountImpl;
template <typename T>
struct CanCountImpl<T, std::false_type>
{
using TTraits = vtkm::TypeTraits<T>;
static constexpr bool IsNumeric =
!std::is_same<typename TTraits::NumericTag, vtkm::TypeTraitsUnknownTag>::value;
static constexpr bool value = IsNumeric;
};
template <typename T>
struct CanCountImpl<T, std::true_type>
struct CanCountImpl
{
using VTraits = vtkm::VecTraits<T>;
using BaseType = typename VTraits::BaseComponentType;
using TTraits = vtkm::TypeTraits<BaseType>;
static constexpr bool IsNumeric =
!std::is_same<typename TTraits::NumericTag, vtkm::TypeTraitsUnknownTag>::value;
static constexpr bool IsBool = std::is_same<BaseType, bool>::value;
static constexpr bool value = CanCountImpl<BaseType, std::false_type>::value && !IsBool;
static constexpr bool value = IsNumeric && !IsBool;
};
} // namespace detail
@ -152,6 +143,52 @@ make_ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm::
{
return vtkm::cont::ArrayHandleCounting<CountingValueType>(start, step, length);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCounting>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>& input,
vtkm::cont::DeviceAdapterId) const
{
using Traits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(Traits::NUM_COMPONENTS);
auto portal = result.WritePortal();
if (portal.GetNumberOfValues() > 0)
{
T first = input.ReadPortal().Get(0);
T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1);
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
}
else
{
// Array is empty
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
portal.Set(cIndex, vtkm::Range{});
}
}
return result;
}
};
} // namespace internal
}
} // namespace vtkm::cont

@ -47,7 +47,7 @@ public:
{
}
/// Copy constructor for any other ArrayPortalConcatenate with a portal type
/// Copy constructor for any other ArrayPortalGroupVecVariable with a portal type
/// that can be copied to this portal type. This allows us to do any type
/// casting that the portals do (like the non-const to const cast).
VTKM_SUPPRESS_EXEC_WARNINGS
@ -77,12 +77,19 @@ public:
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
void Set(vtkm::Id index, const ValueType& value) const
{
// The ValueType (VecFromPortal) operates on demand. Thus, if you set
// something in the value, it has already been passed to the array. Perhaps
// we should check to make sure that the value used matches the location
// you are trying to set in the array, but we don't do that.
if ((&value.GetPortal() == &this->ComponentsPortal) &&
(value.GetOffset() == this->OffsetsPortal.Get(index)))
{
// The ValueType (VecFromPortal) operates on demand. Thus, if you set
// something in the value, it has already been passed to the array.
}
else
{
// The value comes from somewhere else. Copy data in.
this->Get(index) = value;
}
}
VTKM_SUPPRESS_EXEC_WARNINGS
@ -237,13 +244,15 @@ public:
/// it contains three values of Vec-like objects with the data [0,1,2,3],
/// [4,5], and [6,7,8].
///
/// Note that this version of \c ArrayHandle breaks some of the assumptions
/// about \c ArrayHandle a little bit. Typically, there is exactly one type for
/// every value in the array, and this value is also the same between the
/// control and execution environment. However, this class uses \c
/// VecFromPortal it implement a Vec-like class that has a variable number of
/// values, and this type can change between control and execution
/// environments.
/// Note that caution should be used with `ArrayHandleRuntimeVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `VecFromPortal` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `VecFromPortal`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
/// like `+=` do work because they are given an existing variable to place the
/// output.)
///
/// The offsets array is often derived from a list of sizes for each of the
/// entries. You can use the convenience function \c

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_ArrayHandleIndex_h
#define vtk_m_cont_ArrayHandleIndex_h
#include <vtkm/Range.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
namespace vtkm
@ -71,6 +72,29 @@ VTKM_CONT inline vtkm::cont::ArrayHandleIndex make_ArrayHandleIndex(vtkm::Id len
{
return vtkm::cont::ArrayHandleIndex(length);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagIndex>
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId) const
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
return result;
}
};
} // namespace internal
}
} // namespace vtkm::cont

@ -15,8 +15,6 @@
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/VecVariable.h>
#include <vtkm/internal/ArrayPortalValueReference.h>
namespace vtkm
@ -89,7 +87,7 @@ public:
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator=(const T& src)
{
this->DoCopy(src);
@ -106,7 +104,7 @@ public:
return result;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator+=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -117,7 +115,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator-=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -128,7 +126,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator*=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -139,7 +137,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator/=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -150,7 +148,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator%=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -161,7 +159,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator&=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -172,7 +170,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator|=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -183,7 +181,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator^=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -194,7 +192,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator>>=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -205,7 +203,7 @@ public:
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
template <typename T>
VTKM_EXEC_CONT RecombineVec& operator<<=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
@ -437,7 +435,7 @@ public:
using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
using WritePortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
VTKM_CONT static vtkm::IdComponent NumberOfComponents(
VTKM_CONT static vtkm::IdComponent GetNumberOfComponents(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return static_cast<vtkm::IdComponent>(
@ -455,7 +453,7 @@ public:
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
for (vtkm::IdComponent component = 0; component < numComponents; ++component)
{
SourceStorage::ResizeBuffers(
@ -477,7 +475,7 @@ public:
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
@ -515,7 +513,7 @@ public:
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
@ -586,9 +584,13 @@ public:
///
/// Note that caution should be used with `ArrayHandleRecombineVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a `VecVariable`, which can cause surprises
/// if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` expression
/// does not exist.
/// type of this array is forced to a special `RecombineVec` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `RecombineVec`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
/// like `+=` do work because they are given an existing variable to place the
/// output.)
///
template <typename ComponentType>
class ArrayHandleRecombineVec
@ -608,7 +610,7 @@ private:
public:
vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::NumberOfComponents(this->GetBuffers());
return StorageType::GetNumberOfComponents(this->GetBuffers());
}
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(

@ -0,0 +1,504 @@
//============================================================================
// 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_ArrayHandleRuntimeVec_h
#define vtk_m_cont_ArrayHandleRuntimeVec_h
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayPortal.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/Assert.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/VecFromPortal.h>
#include <vtkm/VecTraits.h>
namespace vtkm
{
namespace internal
{
namespace detail
{
template <typename T>
struct UnrollVecImpl
{
using type = vtkm::Vec<T, 1>;
};
template <typename T, vtkm::IdComponent N>
struct UnrollVecImpl<vtkm::Vec<T, N>>
{
using subtype = typename UnrollVecImpl<T>::type;
using type = vtkm::Vec<typename subtype::ComponentType, subtype::NUM_COMPONENTS * N>;
};
} // namespace detail
// A helper class that unrolls a nested `Vec` to a single layer `Vec`. This is similar
// to `vtkm::VecFlat`, except that this only flattens `vtkm::Vec<T,N>` objects, and not
// any other `Vec`-like objects. The reason is that a `vtkm::Vec<T,N>` is the same as N
// consecutive `T` objects whereas the same may not be said about other `Vec`-like objects.
template <typename T>
using UnrollVec = typename detail::UnrollVecImpl<T>::type;
template <typename ComponentsPortalType>
class VTKM_ALWAYS_EXPORT ArrayPortalRuntimeVec
{
public:
using ComponentType = typename std::remove_const<typename ComponentsPortalType::ValueType>::type;
using ValueType = vtkm::VecFromPortal<ComponentsPortalType>;
ArrayPortalRuntimeVec() = default;
VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ComponentsPortalType& componentsPortal,
vtkm::IdComponent numComponents)
: ComponentsPortal(componentsPortal)
, NumberOfComponents(numComponents)
{
}
/// Copy constructor for any other ArrayPortalRuntimeVec with a portal type
/// that can be copied to this portal type. This allows us to do any type
/// casting that the portals do (like the non-const to const cast).
template <typename OtherComponentsPortalType>
VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ArrayPortalRuntimeVec<OtherComponentsPortalType>& src)
: ComponentsPortal(src.GetComponentsPortal())
, NumberOfComponents(src.GetNumberOfComponents())
{
}
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const
{
return this->ComponentsPortal.GetNumberOfValues() / this->NumberOfComponents;
}
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const
{
return ValueType(
this->ComponentsPortal, this->NumberOfComponents, index * this->NumberOfComponents);
}
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
if ((&value.GetPortal() == &this->ComponentsPortal) &&
(value.GetOffset() == (index * this->NumberOfComponents)))
{
// The ValueType (VecFromPortal) operates on demand. Thus, if you set
// something in the value, it has already been passed to the array.
}
else
{
// The value comes from somewhere else. Copy data in.
this->Get(index) = value;
}
}
VTKM_EXEC_CONT const ComponentsPortalType& GetComponentsPortal() const
{
return this->ComponentsPortal;
}
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
{
return this->NumberOfComponents;
}
private:
ComponentsPortalType ComponentsPortal;
vtkm::IdComponent NumberOfComponents = 0;
};
}
} // namespace vtkm::internal
namespace vtkm
{
namespace cont
{
struct VTKM_ALWAYS_EXPORT StorageTagRuntimeVec
{
};
namespace internal
{
template <typename ComponentsPortal>
class Storage<vtkm::VecFromPortal<ComponentsPortal>, vtkm::cont::StorageTagRuntimeVec>
{
using ComponentType = typename ComponentsPortal::ValueType;
using ComponentsStorage =
vtkm::cont::internal::Storage<ComponentType, vtkm::cont::StorageTagBasic>;
VTKM_STATIC_ASSERT_MSG(
vtkm::VecTraits<ComponentType>::NUM_COMPONENTS == 1,
"ArrayHandleRuntimeVec only supports scalars grouped into a single Vec. Nested Vecs can "
"still be used with ArrayHandleRuntimeVec. The values are treated as flattened (like "
"with VecFlat).");
using ComponentsArray = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
VTKM_STATIC_ASSERT_MSG(
(std::is_same<ComponentsPortal, typename ComponentsStorage::WritePortalType>::value),
"Used invalid ComponentsPortal type with expected ComponentsStorageTag.");
struct Info
{
vtkm::IdComponent NumberOfComponents;
};
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> ComponentsBuffers(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + 1, buffers.end());
}
public:
using ReadPortalType =
vtkm::internal::ArrayPortalRuntimeVec<typename ComponentsStorage::ReadPortalType>;
using WritePortalType =
vtkm::internal::ArrayPortalRuntimeVec<typename ComponentsStorage::WritePortalType>;
VTKM_CONT static vtkm::IdComponent GetNumberOfComponents(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers[0].GetMetaData<Info>().NumberOfComponents;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return ComponentsStorage::GetNumberOfValues(ComponentsBuffers(buffers)) /
GetNumberOfComponents(buffers);
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
ComponentsStorage::ResizeBuffers(
numValues * GetNumberOfComponents(buffers), ComponentsBuffers(buffers), preserve, token);
}
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
const vtkm::VecFromPortal<ComponentsPortal>&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleRuntimeVec.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(
ComponentsStorage::CreateReadPortal(ComponentsBuffers(buffers), device, token),
GetNumberOfComponents(buffers));
}
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(
ComponentsStorage::CreateWritePortal(ComponentsBuffers(buffers), device, token),
GetNumberOfComponents(buffers));
}
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
vtkm::IdComponent numComponents = 1,
const ComponentsArray& componentsArray = ComponentsArray{})
{
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Warn,
(componentsArray.GetNumberOfValues() % numComponents) != 0,
"Array given to ArrayHandleRuntimeVec has size ("
<< componentsArray.GetNumberOfValues()
<< ") that is not divisible by the number of components selected ("
<< numComponents << ").");
Info info;
info.NumberOfComponents = numComponents;
return vtkm::cont::internal::CreateBuffers(info, componentsArray);
}
VTKM_CONT static ComponentsArray GetComponentsArray(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return ComponentsArray(ComponentsBuffers(buffers));
}
VTKM_CONT static void AsArrayHandleBasic(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>& dest)
{
if (GetNumberOfComponents(buffers) != 1)
{
throw vtkm::cont::ErrorBadType(
"Attempted to pull a scalar array from an ArrayHandleRuntime that does not hold scalars.");
}
dest = GetComponentsArray(buffers);
}
template <vtkm::IdComponent N>
VTKM_CONT static void AsArrayHandleBasic(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, N>, vtkm::cont::StorageTagBasic>& dest)
{
if (GetNumberOfComponents(buffers) != N)
{
throw vtkm::cont::ErrorBadType(
"Attempted to pull an array of Vecs of the wrong size from an ArrayHandleRuntime.");
}
dest = vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, N>, vtkm::cont::StorageTagBasic>(
ComponentsBuffers(buffers));
}
template <typename T, vtkm::IdComponent NInner, vtkm::IdComponent NOuter>
VTKM_CONT static void AsArrayHandleBasic(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<T, NInner>, NOuter>, vtkm::cont::StorageTagBasic>&
dest)
{
// Flatten the Vec by one level and attempt to get the array handle for that.
vtkm::cont::ArrayHandleBasic<vtkm::Vec<T, NInner * NOuter>> squashedArray;
AsArrayHandleBasic(buffers, squashedArray);
// Now unsquash the array by stealling the buffers and creating an array of the right type
dest =
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<T, NInner>, NOuter>, vtkm::cont::StorageTagBasic>(
squashedArray.GetBuffers());
}
};
} // namespace internal
/// \brief Fancy array handle for a basic array with runtime selected vec size.
///
/// It is sometimes the case that you need to create an array of `Vec`s where
/// the number of components is not known until runtime. This is problematic
/// for normal `ArrayHandle`s because you have to specify the size of the `Vec`s
/// as a template parameter at compile time. `ArrayHandleRuntimeVec` can be used
/// in this case.
///
/// Note that caution should be used with `ArrayHandleRuntimeVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `VecFromPortal` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `VecFromPortal`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
/// like `+=` do work because they are given an existing variable to place the
/// output.)
///
/// It is possible to provide an `ArrayHandleBasic` of the same component
/// type as the underlying storage for this array. In this case, the array
/// will be accessed much in the same manner as `ArrayHandleGroupVec`.
///
/// `ArrayHandleRuntimeVec` also allows you to convert the array to an
/// `ArrayHandleBasic` of the appropriate `Vec` type (or `component` type).
/// A runtime check will be performed to make sure the number of components
/// matches.
///
template <typename ComponentType>
class ArrayHandleRuntimeVec
: public vtkm::cont::ArrayHandle<
vtkm::VecFromPortal<typename ArrayHandleBasic<ComponentType>::WritePortalType>,
vtkm::cont::StorageTagRuntimeVec>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleRuntimeVec,
(ArrayHandleRuntimeVec<ComponentType>),
(vtkm::cont::ArrayHandle<
vtkm::VecFromPortal<typename ArrayHandleBasic<ComponentType>::WritePortalType>,
vtkm::cont::StorageTagRuntimeVec>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
using ComponentsArrayType = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
public:
VTKM_CONT
ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
const ComponentsArrayType& componentsArray = ComponentsArrayType{})
: Superclass(StorageType::CreateBuffers(numComponents, componentsArray))
{
}
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::GetNumberOfComponents(this->GetBuffers());
}
VTKM_CONT vtkm::cont::ArrayHandleBasic<ComponentType> GetComponentsArray() const
{
return StorageType::GetComponentsArray(this->GetBuffers());
}
///@{
/// \brief Converts the array to that of a basic array handle.
///
/// This method converts the `ArrayHandleRuntimeVec` to a simple `ArrayHandleBasic`.
/// This is useful if the `ArrayHandleRuntimeVec` is passed to a routine that works
/// on an array of a specific `Vec` size (or scalars). After a runtime check, the
/// array can be converted to a typical array and used as such.
template <typename ValueType>
void AsArrayHandleBasic(vtkm::cont::ArrayHandle<ValueType>& array) const
{
StorageType::AsArrayHandleBasic(this->GetBuffers(), array);
}
template <typename ArrayType>
ArrayType AsArrayHandleBasic() const
{
ArrayType array;
this->AsArrayHandleBasic(array);
return array;
}
///@}
};
/// \c make_ArrayHandleRuntimeVec is convenience function to generate an
/// ArrayHandleRuntimeVec. It takes in an ArrayHandle of values and an
/// array handle of offsets and returns an array handle with consecutive
/// entries grouped in a Vec.
///
template <typename T>
VTKM_CONT auto make_ArrayHandleRuntimeVec(
vtkm::IdComponent numComponents,
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray =
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>{})
{
using UnrolledVec = vtkm::internal::UnrollVec<T>;
using ComponentType = typename UnrolledVec::ComponentType;
// Use some dangerous magic to convert the basic array to its base component and create
// an ArrayHandleRuntimeVec from that.
vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic> flatComponents(
componentsArray.GetBuffers());
return vtkm::cont::ArrayHandleRuntimeVec<ComponentType>(
numComponents * UnrolledVec::NUM_COMPONENTS, flatComponents);
}
template <typename T>
VTKM_CONT auto make_ArrayHandleRuntimeVec(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray)
{
return make_ArrayHandleRuntimeVec(1, componentsArray);
}
namespace internal
{
template <>
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagRuntimeVec>
{
template <typename T>
auto operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
{
using ComponentType = typename T::ComponentType;
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> array{ src };
constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat<ComponentType>::NUM_COMPONENTS;
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> dest =
ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>{}(
array.GetComponentsArray(), componentIndex % NUM_SUB_COMPONENTS, allowCopy);
// Adjust stride and offset to expectations of grouped values
const vtkm::IdComponent numComponents = array.GetNumberOfComponents();
return vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType>(
dest.GetBasicArray(),
dest.GetNumberOfValues() / numComponents,
dest.GetStride() * numComponents,
dest.GetOffset() + (dest.GetStride() * (componentIndex / NUM_SUB_COMPONENTS)),
dest.GetModulo(),
dest.GetDivisor());
}
};
} // namespace internal
}
} // namespace vtkm::cont
//=============================================================================
// Specializations of serialization related classes
/// @cond SERIALIZATION
namespace vtkm
{
namespace cont
{
template <typename T>
struct SerializableTypeString<vtkm::cont::ArrayHandleRuntimeVec<T>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "AH_RuntimeVec<" + SerializableTypeString<T>::Get() + ">";
return name;
}
};
template <typename VecType>
struct SerializableTypeString<vtkm::cont::ArrayHandle<VecType, vtkm::cont::StorageTagRuntimeVec>>
: SerializableTypeString<vtkm::cont::ArrayHandleRuntimeVec<typename VecType::ComponentType>>
{
};
}
} // vtkm::cont
namespace mangled_diy_namespace
{
template <typename T>
struct Serialization<vtkm::cont::ArrayHandleRuntimeVec<T>>
{
private:
using Type = vtkm::cont::ArrayHandleRuntimeVec<T>;
using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
vtkmdiy::save(bb, Type(obj).GetNumberOfComponents());
vtkmdiy::save(bb, Type(obj).GetComponentsArray());
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
{
vtkm::IdComponent numComponents;
vtkm::cont::ArrayHandleBasic<T> componentArray;
vtkmdiy::load(bb, numComponents);
vtkmdiy::load(bb, componentArray);
obj = vtkm::cont::make_ArrayHandleRuntimeVec(numComponents, componentArray);
}
};
template <typename VecType>
struct Serialization<vtkm::cont::ArrayHandle<VecType, vtkm::cont::StorageTagRuntimeVec>>
: Serialization<vtkm::cont::ArrayHandleRuntimeVec<typename VecType::ComponentType>>
{
};
} // diy
/// @endcond SERIALIZATION
#endif //vtk_m_cont_ArrayHandleRuntimeVec_h

@ -44,7 +44,6 @@ public:
private:
using ComponentType = typename ComponentPortalType::ValueType;
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<ValueType>::value);
using VTraits = vtkm::VecTraits<ValueType>;
VTKM_STATIC_ASSERT((std::is_same<typename VTraits::ComponentType, ComponentType>::value));
static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS;

@ -86,6 +86,28 @@ ArrayExtractComponentImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
}
}
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range>
ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device)) const
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = input.ReadPortal();
// In this portal we know that the min value is the first entry and the
// max value is the last entry.
vtkm::Vec3f minimum = portal.Get(0);
vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
rangeArray.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));
return rangeArray;
}
} // namespace internal
}

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_ArrayHandleUniformPointCoordinates_h
#define vtk_m_cont_ArrayHandleUniformPointCoordinates_h
#include <vtkm/Range.h>
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/internal/ArrayPortalUniformPointCoordinates.h>
@ -83,6 +84,17 @@ struct VTKM_CONT_EXPORT ArrayExtractComponentImpl<vtkm::cont::StorageTagUniformP
vtkm::CopyFlag allowCopy) const;
};
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoints>
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
vtkm::cont::DeviceAdapterId device) const;
};
} // namespace internal
}

@ -12,118 +12,16 @@
#include <vtkm/TypeList.h>
namespace vtkm
{
namespace cont
{
void ThrowArrayRangeComputeFailed()
{
throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device.");
}
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(T, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(T, N, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(Storage) \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int8, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt8, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int16, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt16, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(char, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(signed VTKM_UNUSED_INT_TYPE, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(unsigned VTKM_UNUSED_INT_TYPE, Storage)
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(N, Storage) \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int8, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt8, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int16, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt16, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(char, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage)
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagStride);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates);
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC
// Special implementation for regular point coordinates, which are easy
// to determine.
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::DeviceAdapterId)
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.ReadPortal();
// In this portal we know that the min value is the first entry and the
// max value is the last entry.
vtkm::Vec3f minimum = portal.Get(0);
vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
rangeArray.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));
return rangeArray;
}
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId)
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
return result;
}
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleXGCCoordinates.h>
namespace
{
@ -152,7 +50,7 @@ struct ComputeRangeFunctor
vtkm::cont::DeviceAdapterId device,
vtkm::cont::ArrayHandle<vtkm::Range>& ranges) const
{
ranges = vtkm::cont::ArrayRangeCompute(array, device);
ranges = vtkm::cont::ArrayRangeComputeTemplate(array, device);
}
// Used with vtkm::ListForEach to get components
@ -172,7 +70,7 @@ struct ComputeRangeFunctor
{
vtkm::cont::ArrayHandleStride<T> componentArray = array.ExtractComponent<T>(componentI);
vtkm::cont::ArrayHandle<vtkm::Range> componentRange =
vtkm::cont::ArrayRangeCompute(componentArray, device);
vtkm::cont::ArrayRangeComputeTemplate(componentArray, device);
rangePortal.Set(componentI, componentRange.ReadPortal().Get(0));
}
success = true;
@ -191,6 +89,21 @@ vtkm::cont::ArrayHandle<vtkm::Range> ComputeForStorage(const vtkm::cont::Unknown
} // anonymous namespace
namespace vtkm
{
namespace cont
{
namespace internal
{
void ThrowArrayRangeComputeFailed()
{
throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device.");
}
} // namespace internal
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device)
{
@ -214,7 +127,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::Unknown
{
vtkm::cont::ArrayHandleUniformPointCoordinates uniformPoints;
array.AsArrayHandle(uniformPoints);
return vtkm::cont::ArrayRangeCompute(uniformPoints, device);
return vtkm::cont::ArrayRangeComputeTemplate(uniformPoints, device);
}
using CartesianProductStorage =
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
@ -234,7 +147,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::Unknown
}
if (array.IsStorageType<vtkm::cont::StorageTagIndex>())
{
return ArrayRangeCompute(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
return ArrayRangeComputeTemplate(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
}
}
catch (vtkm::cont::ErrorBadType&)

@ -31,7 +31,6 @@ namespace vtkm
namespace cont
{
///@{
/// \brief Compute the range of the data in an array handle.
///
/// Given an `ArrayHandle`, this function computes the range (min and max) of
@ -48,179 +47,27 @@ namespace cont
/// Note that the ArrayRangeCompute.h header file contains only precompiled overloads
/// of ArrayRangeCompute. This is so that ArrayRangeCompute.h can be included in
/// code that does not use a device compiler. If you need to compute array ranges
/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to include
/// ArrayRangeComputeTemplate.h. This contains a templated version of ArrayRangeCompute
/// that will compile for any `ArrayHandle` type not already handled.
/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to use
/// `ArrayRangeComputeTemplate` (declared in `ArrayRangeComputeTemplate`), which
/// will compile for any `ArrayHandle` type not already handled.
///
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(T, Storage) \
VTKM_CONT_EXPORT \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, \
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(T, N, Storage) \
VTKM_CONT_EXPORT \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(Storage) \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int8, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt8, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int16, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt16, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(char, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(signed VTKM_UNUSED_INT_TYPE, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(unsigned VTKM_UNUSED_INT_TYPE, Storage)
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(N, Storage) \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int8, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt8, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int16, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt16, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(char, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage)
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagStride);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates);
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC
VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Implementation of cartesian products
template <typename T, typename ST1, typename ST2, typename ST3>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input_,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
namespace internal
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::Range componentRange;
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>
input = input_;
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetFirstArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(0, componentRange);
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetSecondArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(1, componentRange);
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetThirdArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(2, componentRange);
return result;
}
// Implementation of constant arrays
template <typename T>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{})
{
using Traits = vtkm::VecTraits<T>;
const T value = vtkm::cont::ArrayHandleConstant<T>(input).GetValue();
vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value);
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(numComponents);
auto portal = result.WritePortal();
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto component = Traits::GetComponent(value, cIndex);
portal.Set(cIndex, vtkm::Range(component, component));
}
return result;
}
// Implementation of counting arrays
template <typename T>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{})
{
using Traits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(Traits::NUM_COMPONENTS);
auto portal = result.WritePortal();
if (portal.GetNumberOfValues() > 0)
{
T first = input.ReadPortal().Get(0);
T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1);
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
}
else
{
// Array is empty
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
portal.Set(cIndex, vtkm::Range{});
}
}
return result;
}
// Implementation of index arrays
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
///@}
VTKM_CONT_EXPORT void ThrowArrayRangeComputeFailed();
} // namespace internal
VTKM_DEPRECATED(2.1, "Moved to vtkm::cont::internal.")
inline void ThrowArrayRangeComputeFailed()
{
internal::ThrowArrayRangeComputeFailed();
}
}
} // namespace vtkm::cont

@ -13,6 +13,7 @@
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/Deprecated.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/Algorithm.h>
@ -42,8 +43,13 @@ struct ArrayRangeComputeFunctor
}
};
} // namespace detail
namespace internal
{
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeGeneric(
const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device)
{
@ -74,7 +80,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
initial[1] = T(std::numeric_limits<CT>::lowest());
const bool rangeComputed = vtkm::cont::TryExecuteOnDevice(
device, detail::ArrayRangeComputeFunctor{}, input, initial, result);
device, vtkm::cont::detail::ArrayRangeComputeFunctor{}, input, initial, result);
if (!rangeComputed)
{
ThrowArrayRangeComputeFailed();
@ -93,17 +99,38 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
return range;
}
} // namespace detail
template <typename S>
struct ArrayRangeComputeImpl
{
template <typename T>
vtkm::cont::ArrayHandle<vtkm::Range> operator()(const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device) const
{
return vtkm::cont::internal::ArrayRangeComputeGeneric(input, device);
}
};
} // namespace internal
template <typename ArrayHandleType>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return detail::ArrayRangeComputeImpl(input, device);
return internal::ArrayRangeComputeImpl<typename ArrayHandleType::StorageTag>{}(input, device);
}
template <typename ArrayHandleType>
VTKM_DEPRECATED(2.1, "Use precompiled ArrayRangeCompute or ArrayRangeComputeTemplate.")
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
return ArrayRangeComputeTemplate(input, device);
}
}
} // namespace vtkm::cont

@ -38,6 +38,7 @@ set(headers
ArrayHandleRandomStandardNormal.h
ArrayHandleRandomUniformBits.h
ArrayHandleRandomUniformReal.h
ArrayHandleRuntimeVec.h
ArrayHandleSOA.h
ArrayHandleStride.h
ArrayHandleSwizzle.h
@ -94,6 +95,7 @@ set(headers
ErrorExecution.h
ErrorFilterExecution.h
ErrorInternal.h
ErrorUserAbort.h
ExecutionAndControlObjectBase.h
ExecutionObjectBase.h
Field.h

@ -8,6 +8,10 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetExtrude.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Logging.h>
@ -341,3 +345,30 @@ void DataSet::ConvertToExpected()
} // namespace cont
} // namespace vtkm
namespace mangled_diy_namespace
{
using SerializedCellSetTypes = vtkm::ListAppend<VTKM_DEFAULT_CELL_SET_LIST,
vtkm::List<vtkm::cont::CellSetStructured<1>,
vtkm::cont::CellSetStructured<2>,
vtkm::cont::CellSetStructured<3>,
vtkm::cont::CellSetExplicit<>,
vtkm::cont::CellSetSingleType<>,
vtkm::cont::CellSetExtrude>>;
using DefaultDataSetWithCellTypes = vtkm::cont::DataSetWithCellSetTypes<SerializedCellSetTypes>;
void Serialization<vtkm::cont::DataSet>::save(BinaryBuffer& bb, const vtkm::cont::DataSet& obj)
{
vtkmdiy::save(bb, DefaultDataSetWithCellTypes{ obj });
}
void Serialization<vtkm::cont::DataSet>::load(BinaryBuffer& bb, vtkm::cont::DataSet& obj)
{
DefaultDataSetWithCellTypes data;
vtkmdiy::load(bb, data);
obj = data.DataSet;
}
} // namespace mangled_diy_namespace

@ -420,37 +420,70 @@ namespace vtkm
namespace cont
{
template <typename FieldTypeList = VTKM_DEFAULT_TYPE_LIST,
typename CellSetTypesList = VTKM_DEFAULT_CELL_SET_LIST>
struct SerializableDataSet
/// \brief Specify cell sets to use when serializing a `DataSet`.
///
/// Usually when serializing a `DataSet`, it uses a fixed set of standard
/// `CellSet` types to serialize. If you are writing an algorithm with a
/// custom `CellSet`, you can specify the `CellSet`(s) as the template
/// parameter for this class (either as a list of `CellSet`s or in a
/// single `vtkm::List` parameter).
///
template <typename... CellSetTypes>
struct DataSetWithCellSetTypes
{
SerializableDataSet() = default;
vtkm::cont::DataSet DataSet;
explicit SerializableDataSet(const vtkm::cont::DataSet& dataset)
DataSetWithCellSetTypes() = default;
explicit DataSetWithCellSetTypes(const vtkm::cont::DataSet& dataset)
: DataSet(dataset)
{
}
vtkm::cont::DataSet DataSet;
};
template <typename... CellSetTypes>
struct DataSetWithCellSetTypes<vtkm::List<CellSetTypes...>>
: DataSetWithCellSetTypes<CellSetTypes...>
{
using DataSetWithCellSetTypes<CellSetTypes...>::DataSetWithCellSetTypes;
};
template <typename FieldTypeList = VTKM_DEFAULT_TYPE_LIST,
typename CellSetTypesList = VTKM_DEFAULT_CELL_SET_LIST>
struct VTKM_DEPRECATED(
2.1,
"Serialize DataSet directly or use DataSetWithCellSetTypes for weird CellSets.")
SerializableDataSet : DataSetWithCellSetTypes<CellSetTypesList>
{
using DataSetWithCellSetTypes<CellSetTypesList>::DataSetWithCellSetTypes;
};
}
} // vtkm::cont
namespace mangled_diy_namespace
{
template <typename FieldTypeList, typename CellSetTypesList>
struct Serialization<vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypesList>>
template <>
struct VTKM_CONT_EXPORT Serialization<vtkm::cont::DataSet>
{
static VTKM_CONT void foo();
static VTKM_CONT void save(BinaryBuffer& bb, const vtkm::cont::DataSet& obj);
static VTKM_CONT void load(BinaryBuffer& bb, vtkm::cont::DataSet& obj);
};
template <typename... CellSetTypes>
struct Serialization<vtkm::cont::DataSetWithCellSetTypes<CellSetTypes...>>
{
private:
using Type = vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypesList>;
using Type = vtkm::cont::DataSetWithCellSetTypes<CellSetTypes...>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const Type& serializable)
{
const auto& dataset = serializable.DataSet;
vtkmdiy::save(bb, dataset.GetCellSet().ResetCellSetList(CellSetTypesList{}));
vtkmdiy::save(bb, dataset.GetCellSet().ResetCellSetList(vtkm::List<CellSetTypes...>{}));
vtkm::IdComponent numberOfFields = dataset.GetNumberOfFields();
vtkmdiy::save(bb, numberOfFields);
@ -472,7 +505,7 @@ public:
auto& dataset = serializable.DataSet;
dataset = {}; // clear
vtkm::cont::UncertainCellSet<CellSetTypesList> cells;
vtkm::cont::UncertainCellSet<vtkm::List<CellSetTypes...>> cells;
vtkmdiy::load(bb, cells);
dataset.SetCellSet(cells);
@ -496,6 +529,20 @@ public:
}
};
template <typename... CellSetTypes>
struct Serialization<vtkm::cont::DataSetWithCellSetTypes<vtkm::List<CellSetTypes...>>>
: Serialization<vtkm::cont::DataSetWithCellSetTypes<CellSetTypes...>>
{
};
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename FieldTypeList, typename CellSetTypesList>
struct Serialization<vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypesList>>
: Serialization<vtkm::cont::DataSetWithCellSetTypes<CellSetTypesList>>
{
};
VTKM_DEPRECATED_SUPPRESS_END
} // diy
/// @endcond SERIALIZATION

@ -0,0 +1,42 @@
//============================================================================
// 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_ErrorUserAbort_h
#define vtk_m_cont_ErrorUserAbort_h
#include <vtkm/cont/Error.h>
namespace vtkm
{
namespace cont
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
/// This class is thrown when vtk-m detects a request for aborting execution
/// in the current thread
///
class VTKM_ALWAYS_EXPORT ErrorUserAbort : public Error
{
public:
ErrorUserAbort()
: Error(Message, true)
{
}
private:
static constexpr const char* Message = "User abort detected.";
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::cont
#endif // vtk_m_cont_ErrorUserAbort_h

@ -35,6 +35,7 @@ struct RuntimeDeviceTrackerInternals
std::array<bool, VTKM_MAX_DEVICE_ADAPTER_ID> RuntimeAllowed;
bool ThreadFriendlyMemAlloc = false;
std::function<bool()> AbortChecker;
};
}
@ -186,6 +187,28 @@ VTKM_CONT void RuntimeDeviceTracker::CopyStateFrom(const vtkm::cont::RuntimeDevi
*(this->Internals) = *tracker.Internals;
}
VTKM_CONT
void RuntimeDeviceTracker::SetAbortChecker(const std::function<bool()>& func)
{
this->Internals->AbortChecker = func;
}
VTKM_CONT
bool RuntimeDeviceTracker::CheckForAbortRequest() const
{
if (this->Internals->AbortChecker)
{
return this->Internals->AbortChecker();
}
return false;
}
VTKM_CONT
void RuntimeDeviceTracker::ClearAbortChecker()
{
this->Internals->AbortChecker = nullptr;
}
VTKM_CONT
void RuntimeDeviceTracker::PrintSummary(std::ostream& out) const
{
@ -228,25 +251,6 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Entering scoped runtime region");
}
VTKM_CONT
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode)
: ScopedRuntimeDeviceTracker(GetRuntimeDeviceTracker())
{
if (mode == RuntimeDeviceTrackerMode::Force)
{
this->ForceDevice(device);
}
else if (mode == RuntimeDeviceTrackerMode::Enable)
{
this->ResetDevice(device);
}
else if (mode == RuntimeDeviceTrackerMode::Disable)
{
this->DisableDevice(device);
}
}
VTKM_CONT
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
vtkm::cont::DeviceAdapterId device,
@ -268,6 +272,14 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
}
}
VTKM_CONT ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
const std::function<bool()>& abortChecker,
const vtkm::cont::RuntimeDeviceTracker& tracker)
: ScopedRuntimeDeviceTracker(tracker)
{
this->SetAbortChecker(abortChecker);
}
VTKM_CONT
ScopedRuntimeDeviceTracker::~ScopedRuntimeDeviceTracker()
{

@ -17,6 +17,7 @@
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <functional>
#include <memory>
namespace vtkm
@ -123,6 +124,18 @@ public:
///
VTKM_CONT void CopyStateFrom(const vtkm::cont::RuntimeDeviceTracker& tracker);
///@{
/// \brief Set/Clear the abort checker functor.
///
/// If set the abort checker functor is called by \c TryExecute before scheduling
/// a task on a device from the associated the thread. If the functor returns
/// \e true, an exception is thrown.
VTKM_CONT void SetAbortChecker(const std::function<bool()>& func);
VTKM_CONT void ClearAbortChecker();
///@}
VTKM_CONT bool CheckForAbortRequest() const;
VTKM_CONT void PrintSummary(std::ostream& out) const;
private:
@ -149,82 +162,7 @@ private:
void LogEnabledDevices() const;
};
enum struct RuntimeDeviceTrackerMode
{
Force,
Enable,
Disable
};
/// A class that can be used to determine or modify which device adapter
/// VTK-m algorithms should be run on. This class captures the state
/// of the per-thread device adapter and will revert any changes applied
/// during its lifetime on destruction.
///
///
struct VTKM_CONT_EXPORT ScopedRuntimeDeviceTracker : public vtkm::cont::RuntimeDeviceTracker
{
/// Construct a ScopedRuntimeDeviceTracker where the state of the active devices
/// for the current thread are determined by the parameters to the constructor.
///
/// 'Force'
/// - Force-Enable the provided single device adapter
/// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny
/// 'Enable'
/// - Enable the provided single device adapter if it was previously disabled
/// - Enable all device adapters that are currently disabled when using
/// vtkm::cont::DeviceAdaterTagAny
/// 'Disable'
/// - Disable the provided single device adapter
/// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(
vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode = RuntimeDeviceTrackerMode::Force);
/// Construct a ScopedRuntimeDeviceTracker associated with the thread
/// associated with the provided tracker. The active devices
/// for the current thread are determined by the parameters to the constructor.
///
/// 'Force'
/// - Force-Enable the provided single device adapter
/// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny
/// 'Enable'
/// - Enable the provided single device adapter if it was previously disabled
/// - Enable all device adapters that are currently disabled when using
/// vtkm::cont::DeviceAdaterTagAny
/// 'Disable'
/// - Disable the provided single device adapter
/// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny
///
/// Any modifications to the ScopedRuntimeDeviceTracker will effect what
/// ever thread the \c tracker is associated with, which might not be
/// the thread which ScopedRuntimeDeviceTracker was constructed on.
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode,
const vtkm::cont::RuntimeDeviceTracker& tracker);
/// Construct a ScopedRuntimeDeviceTracker associated with the thread
/// associated with the provided tracker.
///
/// Any modifications to the ScopedRuntimeDeviceTracker will effect what
/// ever thread the \c tracker is associated with, which might not be
/// the thread which ScopedRuntimeDeviceTracker was constructed on.
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(const vtkm::cont::RuntimeDeviceTracker& tracker);
/// Destructor is not thread safe
VTKM_CONT ~ScopedRuntimeDeviceTracker();
private:
std::unique_ptr<detail::RuntimeDeviceTrackerInternals> SavedState;
};
///----------------------------------------------------------------------------
/// \brief Get the \c RuntimeDeviceTracker for the current thread.
///
/// Many features in VTK-m will attempt to run algorithms on the "best
@ -236,6 +174,66 @@ private:
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::RuntimeDeviceTracker& GetRuntimeDeviceTracker();
enum struct RuntimeDeviceTrackerMode
{
Force,
Enable,
Disable
};
///----------------------------------------------------------------------------
/// A class to create a scoped runtime device tracker object. This object captures the state
/// of the per-thread device tracker and will revert any changes applied
/// during its lifetime on destruction.
///
struct VTKM_CONT_EXPORT ScopedRuntimeDeviceTracker : public vtkm::cont::RuntimeDeviceTracker
{
/// Construct a ScopedRuntimeDeviceTracker associated with the thread,
/// associated with the provided tracker (defaults to current thread's tracker).
///
/// Any modifications to the ScopedRuntimeDeviceTracker will effect what
/// ever thread the \c tracker is associated with, which might not be
/// the thread on which the ScopedRuntimeDeviceTracker was constructed.
///
/// Constructors are not thread safe
/// @{
///
VTKM_CONT ScopedRuntimeDeviceTracker(
const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker());
/// Use this constructor to modify the state of the device adapters associated with
/// the provided tracker. Use \p mode with \p device as follows:
///
/// 'Force' (default)
/// - Force-Enable the provided single device adapter
/// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny
/// 'Enable'
/// - Enable the provided single device adapter if it was previously disabled
/// - Enable all device adapters that are currently disabled when using
/// vtkm::cont::DeviceAdaterTagAny
/// 'Disable'
/// - Disable the provided single device adapter
/// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny
///
VTKM_CONT ScopedRuntimeDeviceTracker(
vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode = RuntimeDeviceTrackerMode::Force,
const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker());
/// Use this constructor to set the abort checker functor for the provided tracker.
///
VTKM_CONT ScopedRuntimeDeviceTracker(
const std::function<bool()>& abortChecker,
const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker());
/// Destructor is not thread safe
VTKM_CONT ~ScopedRuntimeDeviceTracker();
private:
std::unique_ptr<detail::RuntimeDeviceTrackerInternals> SavedState;
};
}
} // namespace vtkm::cont

@ -12,6 +12,7 @@
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/ErrorUserAbort.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
namespace vtkm
@ -55,6 +56,13 @@ VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::cont::DeviceAdapterId devi
VTKM_LOG_TRYEXECUTE_FAIL("ErrorBadValue (" << e.GetMessage() << ")", functorName, deviceId);
throw;
}
catch (vtkm::cont::ErrorUserAbort& e)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
e.GetMessage() << " Aborting: " << functorName << ", on device "
<< deviceId.GetName());
throw;
}
catch (vtkm::cont::Error& e)
{
VTKM_LOG_TRYEXECUTE_FAIL(e.GetMessage(), functorName, deviceId);

@ -12,6 +12,7 @@
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/ErrorUserAbort.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
@ -40,6 +41,11 @@ inline bool TryExecuteIfValid(std::true_type,
{
try
{
if (tracker.CheckForAbortRequest())
{
throw vtkm::cont::ErrorUserAbort{};
}
return f(tag, std::forward<Args>(args)...);
}
catch (...)

@ -18,6 +18,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleReverse.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ErrorBadType.h>
@ -45,12 +46,16 @@ struct AllVecImpl<N, vtkm::List<Scalars...>>
template <vtkm::IdComponent N>
using AllVec = typename AllVecImpl<N, vtkm::TypeListBaseC>::type;
template <typename T>
using IsBasicStorage = std::is_same<vtkm::cont::StorageTagBasic, T>;
template <typename List>
using RemoveBasicStorage = vtkm::ListRemoveIf<List, IsBasicStorage>;
using UnknownSerializationTypes =
vtkm::ListAppend<vtkm::TypeListBaseC, AllVec<2>, AllVec<3>, AllVec<4>>;
using UnknownSerializationStorage =
vtkm::ListAppend<VTKM_DEFAULT_STORAGE_LIST,
vtkm::List<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
using UnknownSerializationSpecializedStorage =
vtkm::ListAppend<RemoveBasicStorage<VTKM_DEFAULT_STORAGE_LIST>,
vtkm::List<vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic>,
vtkm::cont::StorageTagConstant,
@ -265,7 +270,7 @@ vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponents() const
{
if (this->Container)
{
return this->Container->NumberOfComponents();
return this->Container->NumberOfComponents(this->Container->ArrayHandlePointer);
}
else
{
@ -277,7 +282,7 @@ VTKM_CONT vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponentsFlat() cons
{
if (this->Container)
{
return this->Container->NumberOfComponentsFlat();
return this->Container->NumberOfComponentsFlat(this->Container->ArrayHandlePointer);
}
else
{
@ -432,30 +437,82 @@ std::string SerializableTypeString<vtkm::cont::UnknownArrayHandle>::Get()
}
} // namespace vtkm::cont
namespace mangled_diy_namespace
namespace
{
void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
const vtkm::cont::UnknownArrayHandle& obj)
enum struct SerializedArrayType : vtkm::UInt8
{
BasicArray = 0,
SpecializedStorage
};
struct SaveBasicArray
{
template <typename ComponentType>
VTKM_CONT void operator()(ComponentType,
mangled_diy_namespace::BinaryBuffer& bb,
const vtkm::cont::UnknownArrayHandle& obj,
bool& saved)
{
// Basic arrays and arrays with compatible layouts can be loaed/saved as an
// ArrayHandleRuntimeVec. Thus, we can load/save them all with one routine.
using ArrayType = vtkm::cont::ArrayHandleRuntimeVec<ComponentType>;
if (!saved && obj.CanConvert<ArrayType>())
{
ArrayType array = obj.AsArrayHandle<ArrayType>();
vtkmdiy::save(bb, SerializedArrayType::BasicArray);
vtkmdiy::save(bb, vtkm::cont::TypeToString<ComponentType>());
vtkmdiy::save(bb, array);
saved = true;
}
}
};
struct LoadBasicArray
{
template <typename ComponentType>
VTKM_CONT void operator()(ComponentType,
mangled_diy_namespace::BinaryBuffer& bb,
vtkm::cont::UnknownArrayHandle& obj,
const std::string& componentTypeString,
bool& loaded)
{
if (!loaded && (componentTypeString == vtkm::cont::TypeToString<ComponentType>()))
{
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> array;
vtkmdiy::load(bb, array);
obj = array;
loaded = true;
}
}
};
VTKM_CONT void SaveSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb,
const vtkm::cont::UnknownArrayHandle& obj)
{
vtkm::IdComponent numComponents = obj.GetNumberOfComponents();
switch (numComponents)
{
case 1:
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
vtkmdiy::save(bb, numComponents);
vtkmdiy::save(bb, obj.ResetTypes<vtkm::TypeListBaseC, UnknownSerializationStorage>());
vtkmdiy::save(bb,
obj.ResetTypes<vtkm::TypeListBaseC, UnknownSerializationSpecializedStorage>());
break;
case 2:
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
vtkmdiy::save(bb, numComponents);
vtkmdiy::save(bb, obj.ResetTypes<AllVec<2>, UnknownSerializationStorage>());
vtkmdiy::save(bb, obj.ResetTypes<AllVec<2>, UnknownSerializationSpecializedStorage>());
break;
case 3:
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
vtkmdiy::save(bb, numComponents);
vtkmdiy::save(bb, obj.ResetTypes<AllVec<3>, UnknownSerializationStorage>());
vtkmdiy::save(bb, obj.ResetTypes<AllVec<3>, UnknownSerializationSpecializedStorage>());
break;
case 4:
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
vtkmdiy::save(bb, numComponents);
vtkmdiy::save(bb, obj.ResetTypes<AllVec<4>, UnknownSerializationStorage>());
vtkmdiy::save(bb, obj.ResetTypes<AllVec<4>, UnknownSerializationSpecializedStorage>());
break;
default:
throw vtkm::cont::ErrorBadType(
@ -465,16 +522,17 @@ void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
}
}
void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
vtkm::cont::UnknownArrayHandle& obj)
VTKM_CONT void LoadSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb,
vtkm::cont::UnknownArrayHandle& obj)
{
vtkm::IdComponent numComponents;
vtkmdiy::load(bb, numComponents);
vtkm::cont::UncertainArrayHandle<vtkm::TypeListBaseC, UnknownSerializationStorage> array1;
vtkm::cont::UncertainArrayHandle<AllVec<2>, UnknownSerializationStorage> array2;
vtkm::cont::UncertainArrayHandle<AllVec<3>, UnknownSerializationStorage> array3;
vtkm::cont::UncertainArrayHandle<AllVec<4>, UnknownSerializationStorage> array4;
vtkm::cont::UncertainArrayHandle<vtkm::TypeListBaseC, UnknownSerializationSpecializedStorage>
array1;
vtkm::cont::UncertainArrayHandle<AllVec<2>, UnknownSerializationSpecializedStorage> array2;
vtkm::cont::UncertainArrayHandle<AllVec<3>, UnknownSerializationSpecializedStorage> array3;
vtkm::cont::UncertainArrayHandle<AllVec<4>, UnknownSerializationSpecializedStorage> array4;
switch (numComponents)
{
@ -499,4 +557,53 @@ void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
}
}
} // anonymous namespace
namespace mangled_diy_namespace
{
void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
const vtkm::cont::UnknownArrayHandle& obj)
{
bool saved = false;
// First, try serializing basic arrays (which we can do for any Vec size).
vtkm::ListForEach(SaveBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, saved);
// If that did not work, try one of the specialized arrays.
if (!saved)
{
SaveSpecializedArray(bb, obj);
}
}
void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
vtkm::cont::UnknownArrayHandle& obj)
{
SerializedArrayType arrayType;
vtkmdiy::load(bb, arrayType);
switch (arrayType)
{
case SerializedArrayType::BasicArray:
{
std::string componentTypeString;
vtkmdiy::load(bb, componentTypeString);
bool loaded = false;
vtkm::ListForEach(
LoadBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, componentTypeString, loaded);
if (!loaded)
{
throw vtkm::cont::ErrorInternal("Failed to load basic array. Unexpected buffer values.");
}
break;
}
case SerializedArrayType::SpecializedStorage:
LoadSpecializedArray(bb, obj);
break;
default:
throw vtkm::cont::ErrorInternal("Got inappropriate enumeration value for loading array.");
}
}
} // namespace mangled_diy_namespace

@ -17,6 +17,7 @@
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/StorageList.h>
@ -42,6 +43,14 @@ void UnknownAHDelete(void* mem)
delete arrayHandle;
}
template <typename T, typename S>
const std::vector<vtkm::cont::internal::Buffer>& UnknownAHBuffers(void* mem)
{
using AH = vtkm::cont::ArrayHandle<T, S>;
AH* arrayHandle = reinterpret_cast<AH*>(mem);
return arrayHandle->GetBuffers();
}
template <typename T, typename S>
void* UnknownAHNewInstance()
{
@ -56,49 +65,86 @@ vtkm::Id UnknownAHNumberOfValues(void* mem)
return arrayHandle->GetNumberOfValues();
}
template <typename T, typename StaticSize = typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic>
struct UnknownAHNumberOfComponentsImpl;
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeStatic>
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsImpl(void* mem)
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
std::vector<vtkm::cont::internal::Buffer>()))
{
static constexpr vtkm::IdComponent Value = vtkm::internal::SafeVecTraits<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeVariable>
{
static constexpr vtkm::IdComponent Value = 0;
};
template <typename T>
vtkm::IdComponent UnknownAHNumberOfComponents()
{
return UnknownAHNumberOfComponentsImpl<T>::Value;
using AH = vtkm::cont::ArrayHandle<T, S>;
AH* arrayHandle = reinterpret_cast<AH*>(mem);
return vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers());
}
template <typename T,
typename = typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic,
typename = vtkm::HasVecTraits<T>>
struct UnknownAHNumberOfComponentsFlatImpl;
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeStatic, std::true_type>
// Uses SFINAE to use the number of compnents in VecTraits.
// Note that this will conflict with the above overloaded function if the storage has a
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
// of a use case for the storage to report the number of components for a static data type.
// If that happens, this implementation will need to be modified.
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsImpl(void*) -> decltype(vtkm::VecTraits<T>::NUM_COMPONENTS)
{
static constexpr vtkm::IdComponent Value = vtkm::VecFlat<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeVariable, std::true_type>
{
static constexpr vtkm::IdComponent Value = 0;
};
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeStatic, std::false_type>
{
static constexpr vtkm::IdComponent Value = 1;
};
static constexpr vtkm::IdComponent numComponents = vtkm::VecTraits<T>::NUM_COMPONENTS;
return numComponents;
}
template <typename T>
vtkm::IdComponent UnknownAHNumberOfComponentsFlat()
// Fallback for when there is no way to determine the number of components. (This could be
// because each value could have a different number of components.
template <typename T, typename S>
inline vtkm::IdComponent UnknownAHNumberOfComponentsImpl(...)
{
return UnknownAHNumberOfComponentsFlatImpl<T>::Value;
return 0;
}
template <typename T, typename S>
vtkm::IdComponent UnknownAHNumberOfComponents(void* mem)
{
return UnknownAHNumberOfComponentsImpl<T, S>(mem);
}
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem)
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
std::vector<vtkm::cont::internal::Buffer>()))
{
using AH = vtkm::cont::ArrayHandle<T, S>;
AH* arrayHandle = reinterpret_cast<AH*>(mem);
// Making an assumption here that `T` is a `Vec`-like object that `GetNumberOfComponents`
// will report on how many each has. Further assuming that the components of `T` are
// static. If a future `ArrayHandle` type violates this, this code will have to become
// more complex.
return (vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers()) *
vtkm::VecFlat<typename vtkm::VecTraits<T>::ComponentType>::NUM_COMPONENTS);
}
// Uses SFINAE to use the number of compnents in VecTraits.
// Note that this will conflict with the above overloaded function if the storage has a
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
// of a use case for the storage to report the number of components for a static data type.
// If that happens, this implementation will need to be modified.
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsFlatImpl(void*)
-> decltype(vtkm::VecTraits<T>::NUM_COMPONENTS)
{
// static constexpr vtkm::IdComponent numComponents = vtkm::VecFlat<T>::NUM_COMPONENTS;
// return numComponents;
return vtkm::VecFlat<T>::NUM_COMPONENTS;
}
// Fallback for when there is no way to determine the number of components. (This could be
// because each value could have a different number of components or just that VecTraits
// are not defined.) Since it cannot be flattened, just return the same as num components.
template <typename T, typename S>
inline vtkm::IdComponent UnknownAHNumberOfComponentsFlatImpl(...)
{
return UnknownAHNumberOfComponentsImpl<T, S>(static_cast<void*>(nullptr));
}
template <typename T, typename S>
vtkm::IdComponent UnknownAHNumberOfComponentsFlat(void* mem)
{
return UnknownAHNumberOfComponentsFlatImpl<T, S>(mem);
}
template <typename T, typename S>
@ -220,6 +266,9 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
using DeleteType = void(void*);
DeleteType* DeleteFunction;
using BuffersType = const std::vector<vtkm::cont::internal::Buffer>&(void*);
BuffersType* Buffers;
using NewInstanceType = void*();
NewInstanceType* NewInstance;
@ -230,7 +279,7 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
using NumberOfValuesType = vtkm::Id(void*);
NumberOfValuesType* NumberOfValues;
using NumberOfComponentsType = vtkm::IdComponent();
using NumberOfComponentsType = vtkm::IdComponent(void*);
NumberOfComponentsType* NumberOfComponents;
NumberOfComponentsType* NumberOfComponentsFlat;
@ -313,14 +362,13 @@ std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic(vtkm::VecTraitsTag
template <typename T>
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic()
{
return UnknownAHNewInstanceBasic<T>(typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic{});
return UnknownAHNewInstanceBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
}
template <typename T>
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(vtkm::VecTraitsTagSizeStatic)
{
using FloatT = typename vtkm::internal::SafeVecTraits<T>::template ReplaceBaseComponentType<
vtkm::FloatDefault>;
using FloatT = typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<vtkm::FloatDefault>;
return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic<FloatT>{});
}
template <typename T>
@ -332,8 +380,7 @@ std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(vtkm::VecTrai
template <typename T>
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic()
{
return UnknownAHNewInstanceFloatBasic<T>(
typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic{});
return UnknownAHNewInstanceFloatBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
}
template <typename T, typename S>
@ -342,14 +389,15 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
, ValueType(typeid(T))
, StorageType(typeid(S))
, BaseComponentType(
UnknownAHComponentInfo::Make<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>())
UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
, DeleteFunction(detail::UnknownAHDelete<T, S>)
, Buffers(detail::UnknownAHBuffers<T, S>)
, NewInstance(detail::UnknownAHNewInstance<T, S>)
, NewInstanceBasic(detail::UnknownAHNewInstanceBasic<T>)
, NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic<T>)
, NumberOfValues(detail::UnknownAHNumberOfValues<T, S>)
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T>)
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T>)
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T, S>)
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T, S>)
, Allocate(detail::UnknownAHAllocate<T, S>)
, ShallowCopy(detail::UnknownAHShallowCopy<T, S>)
, DeepCopy(detail::UnknownAHDeepCopy<T, S>)
@ -607,13 +655,10 @@ public:
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_BEGIN
#endif
///@{
/// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
/// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
///
private:
template <typename T, typename S>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
VTKM_CONT void BaseAsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
{
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
if (!this->IsType<ArrayType>())
@ -625,6 +670,21 @@ public:
array = *reinterpret_cast<ArrayType*>(this->Container->ArrayHandlePointer);
}
public:
///@{
/// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
/// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
///
template <typename T, typename S>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
{
this->BaseAsArrayHandle(array);
}
template <typename T>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const;
template <typename T, typename... Ss>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;
@ -638,6 +698,26 @@ public:
this->AsArrayHandle<ContainedArrayType>());
}
template <typename T>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& array) const
{
using BaseT = typename T::ComponentType;
if (this->IsStorageType<vtkm::cont::StorageTagBasic>() && this->IsBaseComponentType<BaseT>())
{
// Reinterpret the basic array as components, and then wrap that in a runtime vec
// with the correct amount of components.
vtkm::cont::ArrayHandle<BaseT, vtkm::cont::StorageTagBasic> basicArray(
this->Container->Buffers(this->Container->ArrayHandlePointer));
array =
vtkm::cont::ArrayHandleRuntimeVec<BaseT>(this->GetNumberOfComponentsFlat(), basicArray);
}
else
{
this->BaseAsArrayHandle(array);
}
}
template <typename ArrayType>
VTKM_CONT ArrayType AsArrayHandle() const
{
@ -877,6 +957,19 @@ struct UnknownArrayHandleCanConvert
}
};
template <typename T>
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagBasic>
{
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
{
using UnrolledVec = vtkm::internal::UnrollVec<T>;
return (array.IsType<vtkm::cont::ArrayHandleBasic<T>>() ||
(array.IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
array.IsBaseComponentType<typename UnrolledVec::ComponentType>() &&
UnrolledVec::NUM_COMPONENTS == array.GetNumberOfComponentsFlat()));
}
};
template <typename TargetT, typename SourceT, typename SourceS>
struct UnknownArrayHandleCanConvert<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>
{
@ -907,10 +1000,22 @@ struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagMultiplexer<Ss...>>
}
};
template <typename T>
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagRuntimeVec>
{
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
{
using BaseComponentType = typename T::ComponentType;
return (array.IsType<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>>() ||
(array.IsStorageType<vtkm::cont::StorageTagBasic>() &&
array.IsBaseComponentType<BaseComponentType>()));
}
};
} // namespace detail
template <typename ArrayHandleType>
VTKM_CONT bool UnknownArrayHandle::CanConvert() const
VTKM_CONT inline bool UnknownArrayHandle::CanConvert() const
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
@ -921,6 +1026,66 @@ VTKM_CONT bool UnknownArrayHandle::CanConvert() const
namespace detail
{
template <typename T,
vtkm::IdComponent =
vtkm::VecTraits<typename vtkm::internal::UnrollVec<T>::ComponentType>::NUM_COMPONENTS>
struct UnknownArrayHandleRuntimeVecAsBasic
{
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*,
const detail::UnknownAHContainer*,
vtkm::cont::ArrayHandle<T>&) const
{
// This version only gets called if T contains a `Vec`-like object that is not a strict `Vec`.
// This is rare but could happen. In this case, the type cannot be stored in an
// `ArrayHandleRuntimeVec` and therefore the load can never happen, so just ignore.
return false;
}
};
template <typename T>
struct UnknownArrayHandleRuntimeVecAsBasic<T, 1>
{
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle* self,
const detail::UnknownAHContainer* container,
vtkm::cont::ArrayHandle<T>& array) const
{
using UnrolledVec = vtkm::internal::UnrollVec<T>;
using ComponentType = typename UnrolledVec::ComponentType;
if (self->IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
self->IsBaseComponentType<ComponentType>() &&
UnrolledVec::NUM_COMPONENTS == self->GetNumberOfComponentsFlat())
{
// Pull out the components array out of the buffers. The array might not match exactly
// the array put in, but the buffer should still be consistent with the array (which works
// because the size of a basic array is based on the number of bytes in the buffer).
using RuntimeVecType = typename vtkm::cont::ArrayHandleRuntimeVec<ComponentType>::ValueType;
using StorageRuntimeVec =
vtkm::cont::internal::Storage<RuntimeVecType, vtkm::cont::StorageTagRuntimeVec>;
StorageRuntimeVec::AsArrayHandleBasic(container->Buffers(container->ArrayHandlePointer),
array);
return true;
}
else
{
return false;
}
}
};
} // namespace detail
template <typename T>
VTKM_CONT inline void UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const
{
if (!detail::UnknownArrayHandleRuntimeVecAsBasic<T>{}(this, this->Container.get(), array))
{
this->BaseAsArrayHandle(array);
}
}
namespace detail
{
struct UnknownArrayHandleMultiplexerCastTry
{
template <typename T, typename S, typename... Ss>

@ -36,7 +36,6 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
InputPortalType inputPortal,
OutputType& output) const
{
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<OutputType>::value);
if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues()))
{
output = inputPortal.Get(permutationIndex);

@ -32,6 +32,21 @@ VTKM_THIRDPARTY_POST_INCLUDE
#include <type_traits>
#if KOKKOS_VERSION_MAJOR > 3 || (KOKKOS_VERSION_MAJOR == 3 && KOKKOS_VERSION_MINOR >= 7)
#define VTKM_VOLATILE
#else
#define VTKM_VOLATILE volatile
#endif
#if defined(VTKM_ENABLE_KOKKOS_THRUST) && (defined(__HIP__) || defined(__CUDA__))
#define VTKM_USE_KOKKOS_THRUST
#endif
#if defined(VTKM_USE_KOKKOS_THRUST)
#include <thrust/device_ptr.h>
#include <thrust/sort.h>
#endif
namespace vtkm
{
namespace internal
@ -256,7 +271,7 @@ private:
}
KOKKOS_INLINE_FUNCTION
void join(volatile value_type& dst, const volatile value_type& src) const
void join(VTKM_VOLATILE value_type& dst, const VTKM_VOLATILE value_type& src) const
{
dst = this->Operator(dst, src);
}
@ -764,6 +779,88 @@ public:
SortImpl(values, comp, typename std::is_scalar<T>::type{});
}
protected:
// Kokkos currently (11/10/2022) does not support a sort_by_key operator
// so instead we are using thrust if and only if HIP or CUDA are the backends for Kokkos
#if defined(VTKM_USE_KOKKOS_THRUST)
template <typename T, typename U, typename BinaryCompare>
VTKM_CONT static std::enable_if_t<(std::is_same<BinaryCompare, vtkm::SortLess>::value ||
std::is_same<BinaryCompare, vtkm::SortGreater>::value)>
SortByKeyImpl(vtkm::cont::ArrayHandle<T>& keys,
vtkm::cont::ArrayHandle<U>& values,
BinaryCompare,
std::true_type,
std::true_type)
{
vtkm::cont::Token token;
auto keys_portal = keys.PrepareForInPlace(vtkm::cont::DeviceAdapterTagKokkos{}, token);
auto values_portal = values.PrepareForInPlace(vtkm::cont::DeviceAdapterTagKokkos{}, token);
kokkos::internal::KokkosViewExec<T> keys_view(keys_portal.GetArray(),
keys_portal.GetNumberOfValues());
kokkos::internal::KokkosViewExec<U> values_view(values_portal.GetArray(),
values_portal.GetNumberOfValues());
thrust::device_ptr<T> keys_begin(keys_view.data());
thrust::device_ptr<T> keys_end(keys_view.data() + keys_view.size());
thrust::device_ptr<U> values_begin(values_view.data());
if (std::is_same<BinaryCompare, vtkm::SortLess>::value)
{
thrust::sort_by_key(keys_begin, keys_end, values_begin, thrust::less<T>());
}
else
{
thrust::sort_by_key(keys_begin, keys_end, values_begin, thrust::greater<T>());
}
}
#endif
template <typename T,
typename U,
class StorageT,
class StorageU,
class BinaryCompare,
typename ValidKeys,
typename ValidValues>
VTKM_CONT static void SortByKeyImpl(vtkm::cont::ArrayHandle<T, StorageT>& keys,
vtkm::cont::ArrayHandle<U, StorageU>& values,
BinaryCompare binary_compare,
ValidKeys,
ValidValues)
{
// Default to general algorithm
Superclass::SortByKey(keys, values, binary_compare);
}
public:
template <typename T, typename U, class StorageT, class StorageU>
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
vtkm::cont::ArrayHandle<U, StorageU>& values)
{
// Make sure not to use the general algorithm here since
// it will use Sort algorithm instead of SortByKey
SortByKey(keys, values, internal::DefaultCompareFunctor());
}
template <typename T, typename U, class StorageT, class StorageU, class BinaryCompare>
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
vtkm::cont::ArrayHandle<U, StorageU>& values,
BinaryCompare binary_compare)
{
// If T or U are not scalar types, or the BinaryCompare is not supported
// then the general algorithm is called, otherwise we will run thrust
SortByKeyImpl(keys,
values,
binary_compare,
typename std::is_scalar<T>::type{},
typename std::is_scalar<U>::type{});
}
//----------------------------------------------------------------------------
VTKM_CONT static void Synchronize()
{
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance().fence();
@ -794,4 +891,6 @@ public:
}
} // namespace vtkm::cont
#undef VTKM_VOLATILE
#endif //vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h

@ -85,6 +85,7 @@ set(unit_tests_device
UnitTestArrayHandleRandomStandardNormal.cxx
UnitTestArrayHandleRandomUniformReal.cxx
UnitTestArrayHandleRecombineVec.cxx
UnitTestArrayHandleRuntimeVec.cxx
UnitTestArrayHandleSOA.cxx
UnitTestArrayHandleSwizzle.cxx
UnitTestArrayHandleTransform.cxx
@ -122,6 +123,12 @@ if(TARGET vtkm_filter_field_conversion)
)
endif()
if(TARGET vtkm_filter_contour)
list(APPEND unit_tests
UnitTestAbort.cxx
)
endif()
vtkm_unit_tests(SOURCES ${unit_tests} DEVICE_SOURCES ${unit_tests_device})
#add distributed tests i.e.test to run with MPI

@ -0,0 +1,105 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ErrorUserAbort.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/contour/Contour.h>
#include <vtkm/source/Wavelet.h>
#include <sstream>
namespace
{
// A function that checks for abort request.
// This function will be called by `TryExecute` befaure lauching a device task
// to check if abort has been requested.
// For this test case, we are using a simple logic of returning true for the
// `abortAt`th check.
// If this test is failing, one of the things to check would be to see if the
// `Contour` filter has changed such that it no longer has atleast `abortAt`
// task invocations.
bool ShouldAbort()
{
static int abortCheckCounter = 0;
static constexpr int abortAt = 5;
if (++abortCheckCounter >= abortAt)
{
std::cout << "Abort check " << abortCheckCounter << ": true\n";
return true;
}
std::cout << "Abort check " << abortCheckCounter << ": false\n";
return false;
}
int TestAbort()
{
vtkm::source::Wavelet wavelet;
wavelet.SetExtent(vtkm::Id3(-15), vtkm::Id3(16));
auto input = wavelet.Execute();
auto range = input.GetField("RTData").GetRange().ReadPortal().Get(0);
std::vector<vtkm::Float64> isovals;
static constexpr int numDivs = 5;
for (int i = 1; i < numDivs - 1; ++i)
{
auto v = range.Min +
(static_cast<vtkm::Float64>(i) *
((range.Max - range.Min) / static_cast<vtkm::Float64>(numDivs)));
isovals.push_back(v);
}
vtkm::filter::contour::Contour contour;
contour.SetActiveField("RTData");
contour.SetIsoValues(isovals);
// First we will run the filter with the abort function set
std::cout << "Run #1 with the abort function set\n";
try
{
vtkm::cont::ScopedRuntimeDeviceTracker tracker(ShouldAbort);
auto result = contour.Execute(input);
// execution shouldn't reach here
VTKM_TEST_FAIL("Error: filter execution was not aborted. Result: ",
result.GetNumberOfPoints(),
" points and ",
result.GetNumberOfCells(),
" triangles");
}
catch (const vtkm::cont::ErrorUserAbort&)
{
std::cout << "Execution was successfully aborted\n";
}
// Now run the filter without the abort function
std::cout << "Run #2 without the abort function set\n";
try
{
auto result = contour.Execute(input);
std::cout << "Success: filter execution was not aborted. Result: " << result.GetNumberOfPoints()
<< " points and " << result.GetNumberOfCells() << " triangles\n";
}
catch (const vtkm::cont::ErrorUserAbort&)
{
VTKM_TEST_FAIL("Execution was unexpectedly aborted");
}
return 0;
}
} // anon namespace
int UnitTestAbort(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestAbort, argc, argv);
}

@ -17,6 +17,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleReverse.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleView.h>
@ -34,53 +35,79 @@ namespace
constexpr vtkm::Id ARRAY_SIZE = 10;
template <typename T>
vtkm::IdComponent GetTotalNumComponents(const T& vec)
{
using VTraits = vtkm::VecTraits<T>;
if (std::is_same<typename VTraits::ComponentType, typename VTraits::BaseComponentType>::value)
{
return VTraits::GetNumberOfComponents(vec);
}
else
{
return VTraits::GetNumberOfComponents(vec) *
GetTotalNumComponents(VTraits::GetComponent(vec, 0));
}
}
// VecFlat.h has something similar, but it only works with static Vec sizes. It might make sense
// to move this somewhere else later
template <typename BaseComponentType>
struct GetVecFlatIndexImpl
{
template <typename VecType>
VTKM_CONT BaseComponentType operator()(const VecType& vec, vtkm::IdComponent index) const
{
const vtkm::IdComponent subSize = GetTotalNumComponents(vec[0]);
return (*this)(vec[index / subSize], index % subSize);
}
VTKM_CONT BaseComponentType operator()(const BaseComponentType& component,
vtkm::IdComponent index) const
{
VTKM_ASSERT(index == 0);
return component;
}
};
template <typename T>
auto GetVecFlatIndex(const T& vec, vtkm::IdComponent index)
{
return GetVecFlatIndexImpl<typename vtkm::VecTraits<T>::BaseComponentType>{}(vec, index);
}
template <typename T, typename S>
void CheckInputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray,
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::Off)
{
//std::cout << " Checking input array type "
// << vtkm::cont::TypeToString<vtkm::cont::ArrayHandle<T, S>>() << std::endl;
//std::cout << " Original array: ";
//vtkm::cont::printSummary_ArrayHandle(originalArray, std::cout);
using FlatVec = vtkm::VecFlat<T>;
using ComponentType = typename FlatVec::ComponentType;
for (vtkm::IdComponent componentId = 0; componentId < FlatVec::NUM_COMPONENTS; ++componentId)
auto originalPortal = originalArray.ReadPortal();
using ComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
const vtkm::IdComponent numComponents = GetTotalNumComponents(originalPortal.Get(0));
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
{
vtkm::cont::ArrayHandleStride<ComponentType> componentArray =
vtkm::cont::ArrayExtractComponent(originalArray, componentId, allowCopy);
//std::cout << " Component " << componentId << ": ";
//vtkm::cont::printSummary_ArrayHandle(componentArray, std::cout);
auto originalPortal = originalArray.ReadPortal();
auto componentPortal = componentArray.ReadPortal();
VTKM_TEST_ASSERT(originalPortal.GetNumberOfValues() == componentPortal.GetNumberOfValues());
for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex)
{
auto originalValue = vtkm::make_VecFlat(originalPortal.Get(arrayIndex));
auto originalValue = GetVecFlatIndex(originalPortal.Get(arrayIndex), componentId);
ComponentType componentValue = componentPortal.Get(arrayIndex);
VTKM_TEST_ASSERT(test_equal(originalValue[componentId], componentValue));
VTKM_TEST_ASSERT(test_equal(originalValue, componentValue));
}
}
}
template <typename T, typename S>
void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
void CheckOutputArray(
const vtkm::cont::ArrayHandle<T, S>& originalArray,
const vtkm::cont::ArrayHandle<T, S>& outputArray = vtkm::cont::ArrayHandle<T, S>{})
{
CheckInputArray(originalArray);
//std::cout << " Checking output array type "
// << vtkm::cont::TypeToString<vtkm::cont::ArrayHandle<T, S>>() << std::endl;
//std::cout << " Original array: ";
//vtkm::cont::printSummary_ArrayHandle(originalArray, std::cout);
vtkm::cont::ArrayHandle<T, S> outputArray;
using FlatVec = vtkm::VecFlat<T>;
using ComponentType = typename FlatVec::ComponentType;
constexpr vtkm::IdComponent numComponents = FlatVec::NUM_COMPONENTS;
using ComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
const vtkm::IdComponent numComponents = GetTotalNumComponents(originalArray.ReadPortal().Get(0));
// Extract all the stride arrays first, and then allocate them later. This tests to
// to make sure that the independent allocation of all the extracted arrays are consistent
@ -115,18 +142,16 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
}
}
//std::cout << " Output array: ";
//vtkm::cont::printSummary_ArrayHandle(outputArray, std::cout);
auto inPortal = originalArray.ReadPortal();
auto outPortal = outputArray.ReadPortal();
for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex)
{
FlatVec inValue = vtkm::make_VecFlat(inPortal.Get(arrayIndex));
FlatVec outValue = vtkm::make_VecFlat(outPortal.Get(arrayIndex));
auto inValue = inPortal.Get(arrayIndex);
auto outValue = outPortal.Get(arrayIndex);
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
{
VTKM_TEST_ASSERT(test_equal(inValue[componentId], outValue[numComponents - componentId - 1]));
VTKM_TEST_ASSERT(test_equal(GetVecFlatIndex(inValue, componentId),
GetVecFlatIndex(outValue, numComponents - componentId - 1)));
}
}
}
@ -178,9 +203,10 @@ void DoTest()
{
std::cout << "ArrayHandleGroupVec" << std::endl;
vtkm::cont::ArrayHandle<vtkm::Vec3f> array;
array.Allocate(ARRAY_SIZE * 2);
array.Allocate(ARRAY_SIZE * 4);
SetPortal(array.WritePortal());
CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<2>(array));
CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<4>(array));
}
{
@ -202,6 +228,17 @@ void DoTest()
CheckInputArray(vtkm::cont::make_ArrayHandleExtractComponent(compositeArray, 1));
}
{
std::cout << "ArrayHandleRuntimeVec" << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array;
array.Allocate(ARRAY_SIZE * 4);
SetPortal(array.WritePortal());
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(2, array),
vtkm::cont::ArrayHandleRuntimeVec<vtkm::FloatDefault>(2));
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(4, array),
vtkm::cont::ArrayHandleRuntimeVec<vtkm::FloatDefault>(4));
}
{
std::cout << "ArrayHandleCartesianProduct" << std::endl;
vtkm::cont::ArrayHandle<vtkm::Float64> array0;

@ -0,0 +1,248 @@
//============================================================================
// 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/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayHandleGroupVec.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
constexpr vtkm::Id ARRAY_SIZE = 10;
struct UnusualType
{
vtkm::Id X;
};
} // anonymous namespace
namespace detail
{
template <>
struct TestValueImpl<UnusualType>
{
VTKM_EXEC_CONT UnusualType operator()(vtkm::Id index) const
{
return { TestValue(index, decltype(UnusualType::X){}) };
}
};
template <>
struct TestEqualImpl<UnusualType, UnusualType>
{
VTKM_EXEC_CONT bool operator()(UnusualType value1,
UnusualType value2,
vtkm::Float64 tolerance) const
{
return test_equal(value1.X, value2.X, tolerance);
}
};
} // namespace detail
namespace
{
struct PassThrough : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = void(_1, _2);
template <typename InValue, typename OutValue>
VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const
{
vtkm::IdComponent inIndex = 0;
vtkm::IdComponent outIndex = 0;
this->FlatCopy(inValue, inIndex, outValue, outIndex);
}
template <typename InValue, typename OutValue>
VTKM_EXEC void FlatCopy(const InValue& inValue,
vtkm::IdComponent& inIndex,
OutValue& outValue,
vtkm::IdComponent& outIndex) const
{
using VTraitsIn = vtkm::VecTraits<InValue>;
using VTraitsOut = vtkm::VecTraits<OutValue>;
VTraitsOut::SetComponent(outValue, outIndex, VTraitsIn::GetComponent(inValue, inIndex));
inIndex++;
outIndex++;
}
template <typename InComponent, vtkm::IdComponent InN, typename OutValue>
VTKM_EXEC void FlatCopy(const vtkm::Vec<InComponent, InN>& inValue,
vtkm::IdComponent& inIndex,
OutValue& outValue,
vtkm::IdComponent& outIndex) const
{
VTKM_ASSERT(inIndex == 0);
for (vtkm::IdComponent i = 0; i < InN; ++i)
{
FlatCopy(inValue[i], inIndex, outValue, outIndex);
inIndex = 0;
}
}
template <typename InValue, typename OutComponent, vtkm::IdComponent OutN>
VTKM_EXEC void FlatCopy(const InValue& inValue,
vtkm::IdComponent& inIndex,
vtkm::Vec<OutComponent, OutN>& outValue,
vtkm::IdComponent& outIndex) const
{
VTKM_ASSERT(outIndex == 0);
for (vtkm::IdComponent i = 0; i < OutN; ++i)
{
OutComponent outComponent;
FlatCopy(inValue, inIndex, outComponent, outIndex);
outValue[i] = outComponent;
outIndex = 0;
}
}
};
template <vtkm::IdComponent NUM_COMPONENTS>
struct TestRuntimeVecAsInput
{
template <typename ComponentType>
VTKM_CONT void operator()(ComponentType) const
{
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
vtkm::cont::ArrayHandle<ComponentType> baseArray;
baseArray.Allocate(ARRAY_SIZE * NUM_COMPONENTS);
SetPortal(baseArray.WritePortal());
auto runtimeVecArray = vtkm::cont::make_ArrayHandleRuntimeVec(NUM_COMPONENTS, baseArray);
VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE,
"Group array reporting wrong array size.");
vtkm::cont::ArrayHandle<ValueType> resultArray;
vtkm::cont::Invoker{}(PassThrough{}, runtimeVecArray, resultArray);
VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE, "Got bad result array size.");
//verify that the control portal works
vtkm::Id totalIndex = 0;
auto resultPortal = resultArray.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
const ValueType result = resultPortal.Get(index);
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
const ComponentType expectedValue = TestValue(totalIndex, ComponentType());
VTKM_TEST_ASSERT(test_equal(result[componentIndex], expectedValue),
"Result array got wrong value.");
totalIndex++;
}
}
//verify that you can get the data as a basic array
vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, NUM_COMPONENTS>> flatComponents;
runtimeVecArray.AsArrayHandleBasic(flatComponents);
VTKM_TEST_ASSERT(test_equal_ArrayHandles(
flatComponents, vtkm::cont::make_ArrayHandleGroupVec<NUM_COMPONENTS>(baseArray)));
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<ComponentType, 1>, NUM_COMPONENTS>>
nestedComponents;
runtimeVecArray.AsArrayHandleBasic(nestedComponents);
auto flatPortal = flatComponents.ReadPortal();
auto nestedPortal = nestedComponents.ReadPortal();
for (vtkm::Id index = 0; index < flatPortal.GetNumberOfValues(); ++index)
{
VTKM_TEST_ASSERT(test_equal(vtkm::make_VecFlat(flatPortal.Get(index)),
vtkm::make_VecFlat(nestedPortal.Get(index))));
}
runtimeVecArray.ReleaseResources();
}
};
template <vtkm::IdComponent NUM_COMPONENTS>
struct TestRuntimeVecAsOutput
{
template <typename ComponentType>
VTKM_CONT void operator()(ComponentType) const
{
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
vtkm::cont::ArrayHandle<ValueType> baseArray;
baseArray.Allocate(ARRAY_SIZE);
SetPortal(baseArray.WritePortal());
vtkm::cont::ArrayHandle<ComponentType> resultArray;
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> runtimeVecArray(NUM_COMPONENTS, resultArray);
vtkm::cont::Invoker{}(PassThrough{}, baseArray, runtimeVecArray);
VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE,
"Group array reporting wrong array size.");
VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE * NUM_COMPONENTS,
"Got bad result array size.");
//verify that the control portal works
vtkm::Id totalIndex = 0;
auto resultPortal = resultArray.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
const ValueType expectedValue = TestValue(index, ValueType());
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
{
const ComponentType result = resultPortal.Get(totalIndex);
VTKM_TEST_ASSERT(test_equal(result, expectedValue[componentIndex]),
"Result array got wrong value.");
totalIndex++;
}
}
}
};
void Run()
{
using HandleTypesToTest =
vtkm::List<vtkm::Id, vtkm::Vec2i_32, vtkm::FloatDefault, vtkm::Vec3f_64>;
using ScalarTypesToTest = vtkm::List<vtkm::UInt8, vtkm::FloatDefault>;
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRuntimeVec(3) as Input" << std::endl;
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<3>(), HandleTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRuntimeVec(4) as Input" << std::endl;
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<4>(), HandleTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRuntimeVec(2) as Output" << std::endl;
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<2>(), ScalarTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRuntimeVec(3) as Output" << std::endl;
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<3>(), ScalarTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRuntimeVec(3) as Input with unusual type" << std::endl;
TestRuntimeVecAsInput<3>{}(UnusualType{});
}
} // anonymous namespace
int UnitTestArrayHandleRuntimeVec(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
}

@ -11,17 +11,22 @@
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleExtractComponent.h>
#include <vtkm/cont/ArrayHandleGroupVec.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleRandomUniformReal.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/ArrayHandleXGCCoordinates.h>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/Math.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/testing/Testing.h>
@ -31,12 +36,12 @@ namespace
constexpr vtkm::Id ARRAY_SIZE = 20;
template <typename T, typename S>
void CheckRange(const vtkm::cont::ArrayHandle<T, S>& array, bool checkUnknown = true)
void VerifyRange(const vtkm::cont::ArrayHandle<T, S>& array,
const vtkm::cont::ArrayHandle<vtkm::Range>& computedRangeArray)
{
using Traits = vtkm::VecTraits<T>;
vtkm::IdComponent numComponents = Traits::NUM_COMPONENTS;
vtkm::cont::ArrayHandle<vtkm::Range> computedRangeArray = vtkm::cont::ArrayRangeCompute(array);
VTKM_TEST_ASSERT(computedRangeArray.GetNumberOfValues() == numComponents);
auto computedRangePortal = computedRangeArray.ReadPortal();
@ -54,28 +59,12 @@ void CheckRange(const vtkm::cont::ArrayHandle<T, S>& array, bool checkUnknown =
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max));
VTKM_TEST_ASSERT(test_equal(expectedRange, computedRange));
}
}
if (checkUnknown)
{
computedRangeArray = vtkm::cont::ArrayRangeCompute(vtkm::cont::UnknownArrayHandle{ array });
VTKM_TEST_ASSERT(computedRangeArray.GetNumberOfValues() == numComponents);
computedRangePortal = computedRangeArray.ReadPortal();
portal = array.ReadPortal();
for (vtkm::IdComponent component = 0; component < numComponents; ++component)
{
vtkm::Range computedRange = computedRangePortal.Get(component);
vtkm::Range expectedRange;
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
T value = portal.Get(index);
expectedRange.Include(Traits::GetComponent(value, component));
}
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Min));
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max));
VTKM_TEST_ASSERT(test_equal(expectedRange, computedRange));
}
}
template <typename T, typename S>
void CheckRange(const vtkm::cont::ArrayHandle<T, S>& array)
{
VerifyRange(array, vtkm::cont::ArrayRangeCompute(array));
}
template <typename T, typename S>
@ -119,7 +108,7 @@ void TestSOAArray(vtkm::TypeTraitsScalarTag)
}
template <typename T>
void TestStrideArray(vtkm::TypeTraitsScalarTag)
void TestStrideArray()
{
std::cout << "Checking stride array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
@ -127,6 +116,16 @@ void TestStrideArray(vtkm::TypeTraitsScalarTag)
CheckRange(vtkm::cont::ArrayHandleStride<T>(array, ARRAY_SIZE / 2, 2, 1));
}
template <typename T>
void TestCastArray()
{
std::cout << "Checking cast array" << std::endl;
using CastType = typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<vtkm::Float64>;
vtkm::cont::ArrayHandle<T> array;
FillArray(array);
CheckRange(vtkm::cont::make_ArrayHandleCast<CastType>(array));
}
template <typename T>
void TestCartesianProduct(vtkm::TypeTraitsScalarTag)
{
@ -151,7 +150,7 @@ void TestCartesianProduct(vtkm::TypeTraitsVectorTag)
template <typename T>
void TestComposite(vtkm::TypeTraitsScalarTag)
{
std::cout << "Checking composite vector" << std::endl;
std::cout << "Checking composite vector array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array0;
FillArray(array0);
@ -169,6 +168,32 @@ void TestComposite(vtkm::TypeTraitsVectorTag)
// Skip test.
}
template <typename T>
void TestGroup(vtkm::TypeTraitsScalarTag)
{
std::cout << "Checking group vec array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
CheckRange(vtkm::cont::make_ArrayHandleGroupVec<2>(array));
}
template <typename T>
void TestGroup(vtkm::TypeTraitsVectorTag)
{
// Skip test.
}
template <typename T>
void TestView()
{
std::cout << "Checking view array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
CheckRange(vtkm::cont::make_ArrayHandleView(array, 2, ARRAY_SIZE - 5));
}
template <typename T>
void TestConstant()
{
@ -205,15 +230,29 @@ void TestUniformPointCoords()
vtkm::cont::ArrayHandleUniformPointCoordinates(vtkm::Id3(ARRAY_SIZE, ARRAY_SIZE, ARRAY_SIZE)));
}
void TestXGCCoordinates()
{
std::cout << "Checking XGC coordinates array" << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array;
FillArray(array);
CheckRange(vtkm::cont::make_ArrayHandleXGCCoordinates(array, 4, true));
}
struct DoTestFunctor
{
template <typename T>
void operator()(T) const
{
typename vtkm::TypeTraits<T>::DimensionalityTag dimensionality{};
TestBasicArray<T>();
TestSOAArray<T>(typename vtkm::TypeTraits<T>::DimensionalityTag{});
TestCartesianProduct<T>(typename vtkm::TypeTraits<T>::DimensionalityTag{});
TestComposite<T>(typename vtkm::TypeTraits<T>::DimensionalityTag{});
TestSOAArray<T>(dimensionality);
TestStrideArray<T>();
TestCastArray<T>();
TestCartesianProduct<T>(dimensionality);
TestComposite<T>(dimensionality);
TestGroup<T>(dimensionality);
TestView<T>();
TestConstant<T>();
TestCounting<T>(typename std::is_signed<typename vtkm::VecTraits<T>::ComponentType>::type{});
}
@ -226,6 +265,7 @@ void DoTest()
std::cout << "*** Specific arrays *****************" << std::endl;
TestIndex();
TestUniformPointCoords();
TestXGCCoordinates();
}
} // anonymous namespace

@ -24,6 +24,25 @@
#include <cstdio>
#if defined(KOKKOS_ENABLE_SYCL)
#define DEVICE_ASSERT_MSG(cond, message) \
do \
{ \
if (!(cond)) \
{ \
return false; \
} \
} while (false)
#define DEVICE_ASSERT(cond) \
do \
{ \
if (!(cond)) \
{ \
return false; \
} \
} while (false)
#else
#define DEVICE_ASSERT_MSG(cond, message) \
do \
{ \
@ -47,6 +66,7 @@
return false; \
} \
} while (false)
#endif
// Test with some trailing bits in partial last word:
#define NUM_BITS \

@ -22,6 +22,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleReverse.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleSwizzle.h>
#include <vtkm/cont/ArrayHandleTransform.h>
@ -303,6 +304,19 @@ struct TestArrayHandleGroupVecVariable
}
};
struct TestArrayHandleRuntimeVec
{
template <typename T>
void operator()(T) const
{
auto numComps = RandomValue<vtkm::IdComponent>::Make(1, 5);
auto flat = RandomArrayHandle<T>::Make(ArraySize * numComps);
auto array = vtkm::cont::make_ArrayHandleRuntimeVec(numComps, flat);
RunTest(array);
RunTest(MakeTestUnknownArrayHandle(array));
}
};
void TestArrayHandleIndex()
{
auto size = RandomValue<vtkm::Id>::Make(2, 10);
@ -413,6 +427,9 @@ void TestArrayHandleSerialization()
std::cout << "Testing ArrayHandleGroupVecVariable\n";
vtkm::testing::Testing::TryTypes(TestArrayHandleGroupVecVariable(), TestTypesList());
std::cout << "Testing ArrayHandleRuntimeVec\n";
vtkm::testing::Testing::TryTypes(TestArrayHandleRuntimeVec(), TestTypesList());
std::cout << "Testing ArrayHandleIndex\n";
TestArrayHandleIndex();

@ -22,16 +22,26 @@ using CellSetTypes = vtkm::List<vtkm::cont::CellSetExplicit<>,
vtkm::cont::CellSetStructured<2>,
vtkm::cont::CellSetStructured<3>>;
using DataSetWrapper = vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypes>;
using DataSetWrapper = vtkm::cont::DataSetWithCellSetTypes<CellSetTypes>;
VTKM_CONT void TestEqualDataSet(const DataSetWrapper& ds1, const DataSetWrapper& ds2)
VTKM_CONT void TestEqualDataSetWrapper(const DataSetWrapper& ds1, const DataSetWrapper& ds2)
{
VTKM_TEST_ASSERT(test_equal_DataSets(ds1.DataSet, ds2.DataSet, CellSetTypes{}));
}
VTKM_CONT void TestEqualDataSet(const vtkm::cont::DataSet& ds1, const vtkm::cont::DataSet& ds2)
{
VTKM_TEST_ASSERT(test_equal_DataSets(ds1, ds2, CellSetTypes{}));
}
void RunTest(const vtkm::cont::DataSet& ds)
{
TestSerialization(DataSetWrapper(ds), TestEqualDataSet);
VTKM_DEPRECATED_SUPPRESS_BEGIN
TestSerialization(vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypes>(ds),
TestEqualDataSetWrapper);
VTKM_DEPRECATED_SUPPRESS_END
TestSerialization(DataSetWrapper(ds), TestEqualDataSetWrapper);
TestSerialization(ds, TestEqualDataSet);
}
void TestDataSetSerialization()

@ -16,6 +16,7 @@
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/TypeTraits.h>
@ -542,6 +543,57 @@ void TrySetMultiplexerArray()
CheckUnknownArray<vtkm::List<vtkm::Id>, vtkm::List<VTKM_DEFAULT_STORAGE_TAG>>(unknownArray, 1);
}
template <typename T>
void TryConvertRuntimeVec()
{
using BasicArrayType = vtkm::cont::ArrayHandle<T>;
using BasicComponentType = typename vtkm::VecFlat<T>::ComponentType;
constexpr vtkm::IdComponent numFlatComponents = vtkm::VecFlat<T>::NUM_COMPONENTS;
using RuntimeArrayType = vtkm::cont::ArrayHandleRuntimeVec<BasicComponentType>;
std::cout << " Get basic array as ArrayHandleRuntimeVec" << std::endl;
BasicArrayType inputArray;
inputArray.Allocate(ARRAY_SIZE);
SetPortal(inputArray.WritePortal());
vtkm::cont::UnknownArrayHandle unknownWithBasic{ inputArray };
VTKM_TEST_ASSERT(unknownWithBasic.GetNumberOfComponentsFlat() == numFlatComponents);
VTKM_TEST_ASSERT(unknownWithBasic.CanConvert<RuntimeArrayType>());
RuntimeArrayType runtimeArray = unknownWithBasic.AsArrayHandle<RuntimeArrayType>();
// Hack to convert the array handle to a flat array to make it easy to check the runtime array
vtkm::cont::ArrayHandle<vtkm::VecFlat<T>> flatInput{ inputArray.GetBuffers() };
VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatInput, runtimeArray));
std::cout << " Get ArrayHandleRuntimeVec as basic array" << std::endl;
vtkm::cont::UnknownArrayHandle unknownWithRuntimeVec{ runtimeArray };
VTKM_TEST_ASSERT(unknownWithRuntimeVec.GetNumberOfComponentsFlat() == numFlatComponents);
VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert<RuntimeArrayType>());
VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert<BasicArrayType>());
BasicArrayType outputArray = unknownWithRuntimeVec.AsArrayHandle<BasicArrayType>();
VTKM_TEST_ASSERT(test_equal_ArrayHandles(inputArray, outputArray));
}
void TryConvertRuntimeVec()
{
std::cout << " Scalar array." << std::endl;
TryConvertRuntimeVec<vtkm::FloatDefault>();
std::cout << " Equivalent scalar." << std::endl;
TryConvertRuntimeVec<VTKM_UNUSED_INT_TYPE>();
std::cout << " Basic Vec." << std::endl;
TryConvertRuntimeVec<vtkm::Id3>();
std::cout << " Vec of Vecs." << std::endl;
TryConvertRuntimeVec<vtkm::Vec<vtkm::Vec2f, 3>>();
std::cout << " Vec of Vecs of Vecs." << std::endl;
TryConvertRuntimeVec<vtkm::Vec<vtkm::Vec<vtkm::Id4, 3>, 2>>();
}
struct DefaultTypeFunctor
{
template <typename T>
@ -573,6 +625,9 @@ void TestUnknownArrayHandle()
std::cout << "Try setting ArrayHandleMultiplexer" << std::endl;
TrySetMultiplexerArray();
std::cout << "Try converting between ArrayHandleRuntimeVec and basic array" << std::endl;
TryConvertRuntimeVec();
}
} // anonymous namespace

@ -9,6 +9,7 @@ DEPENDS
OPTIONAL_DEPENDS
vtkm_loguru
TEST_OPTIONAL_DEPENDS
vtkm_filter_contour
vtkm_filter_field_conversion
TEST_DEPENDS
vtkm_source

@ -40,7 +40,7 @@ void RunFilter(Filter* self, vtkm::filter::DataSetQueue& input, vtkm::filter::Da
tracker.SetThreadFriendlyMemAlloc(prevVal);
}
}
} // anonymous namespace
Filter::~Filter() = default;
@ -49,6 +49,45 @@ bool Filter::CanThread() const
return true;
}
//----------------------------------------------------------------------------
void Filter::SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass)
{
this->FieldsToPass = fieldsToPass;
}
void Filter::SetFieldsToPass(vtkm::filter::FieldSelection&& fieldsToPass)
{
this->FieldsToPass = std::move(fieldsToPass);
}
void Filter::SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass,
vtkm::filter::FieldSelection::Mode mode)
{
this->FieldsToPass = fieldsToPass;
this->FieldsToPass.SetMode(mode);
}
VTKM_CONT void Filter::SetFieldsToPass(std::initializer_list<std::string> fields,
vtkm::filter::FieldSelection::Mode mode)
{
this->SetFieldsToPass(vtkm::filter::FieldSelection{ fields, mode });
}
void Filter::SetFieldsToPass(
std::initializer_list<std::pair<std::string, vtkm::cont::Field::Association>> fields,
vtkm::filter::FieldSelection::Mode mode)
{
this->SetFieldsToPass(vtkm::filter::FieldSelection{ fields, mode });
}
void Filter::SetFieldsToPass(const std::string& fieldname,
vtkm::cont::Field::Association association,
vtkm::filter::FieldSelection::Mode mode)
{
this->SetFieldsToPass(vtkm::filter::FieldSelection{ fieldname, association, mode });
}
//----------------------------------------------------------------------------
vtkm::cont::PartitionedDataSet Filter::DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& input)

@ -263,27 +263,31 @@ public:
///
/// By default, all fields are passed during execution.
///
VTKM_CONT
void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass)
{
this->FieldsToPass = fieldsToPass;
}
VTKM_CONT void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass);
VTKM_CONT void SetFieldsToPass(vtkm::filter::FieldSelection&& fieldsToPass);
VTKM_CONT
void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass,
vtkm::filter::FieldSelection::Mode mode)
{
this->FieldsToPass = fieldsToPass;
this->FieldsToPass.SetMode(mode);
}
VTKM_DEPRECATED(2.0)
VTKM_CONT void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass,
vtkm::filter::FieldSelection::Mode mode);
VTKM_CONT
void SetFieldsToPass(
VTKM_CONT void SetFieldsToPass(
std::initializer_list<std::string> fields,
vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select);
VTKM_CONT void SetFieldsToPass(
std::initializer_list<std::pair<std::string, vtkm::cont::Field::Association>> fields,
vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select);
VTKM_CONT void SetFieldsToPass(
const std::string& fieldname,
vtkm::cont::Field::Association association,
vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select)
vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select);
VTKM_CONT void SetFieldsToPass(const std::string& fieldname,
vtkm::filter::FieldSelection::Mode mode)
{
this->SetFieldsToPass({ fieldname, association }, mode);
this->SetFieldsToPass(fieldname, vtkm::cont::Field::Association::Any, mode);
}
VTKM_CONT
@ -442,9 +446,12 @@ protected:
{
vtkm::cont::DataSet outDataSet;
outDataSet.SetCellSet(resultCellSet);
outDataSet.AddCoordinateSystem(resultCoordSystem);
vtkm::filter::FieldSelection fieldSelection = this->GetFieldsToPass();
fieldSelection.AddField(resultCoordSystem, vtkm::filter::FieldSelection::Mode::Exclude);
if (this->GetPassCoordinateSystems() || fieldSelection.HasField(resultCoordSystem))
{
outDataSet.AddCoordinateSystem(resultCoordSystem);
fieldSelection.AddField(resultCoordSystem, vtkm::filter::FieldSelection::Mode::Exclude);
}
this->MapFieldsOntoOutput(inDataSet, fieldSelection, outDataSet, fieldMapper);
return outDataSet;
}

@ -29,17 +29,18 @@ bool DoMapField(vtkm::cont::DataSet& result,
{
if (field.IsPointField())
{
vtkm::cont::UnknownArrayHandle inputArray = field.GetData();
vtkm::cont::UnknownArrayHandle outputArray = inputArray.NewInstanceBasic();
auto resolve = [&](const auto& concrete) {
// use std::decay to remove const ref from the decltype of concrete.
using T = typename std::decay_t<decltype(concrete)>::ValueType;
vtkm::cont::ArrayHandle<T> outputArray;
worklet.ProcessPointField(concrete, outputArray);
result.AddPointField(field.GetName(), outputArray);
using BaseT = typename std::decay_t<decltype(concrete)>::ValueType::ComponentType;
auto concreteOut = outputArray.ExtractArrayFromComponents<BaseT>();
worklet.ProcessPointField(concrete, concreteOut);
};
field.GetData()
.CastAndCallForTypesWithFloatFallback<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
resolve);
inputArray.CastAndCallWithExtractedArray(resolve);
result.AddPointField(field.GetName(), outputArray);
return true;
}
else if (field.IsCellField())

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