Merge remote-tracking branch 'origin/master' into update-to-v1.9.0

* origin/master: (331 commits)
  Deprecate old filter base classes and supporting classes
  Remove use of deprecated features in TransferToOpenGL
  Do not overthink ComputeNumberOfBlocksPerAxis
  Revised ComputeNumberOfBlocksPerAxis inspired by Ken Moreland's suggestion
  Replace the way data is split in contour tree augmented example
  diy 2022-09-14 (496253d7)
  Update diy/update.sh
  Fix Fields and CoordinateSystems of Lagrangian filter outputs
  Add more features to Threshold
  Convert LagrangianStructures filter to NewFilter
  Merge branch 'shading_scalarRenderer' of https://gitlab.kitware.com/nicolemarsaglia/vtk-m into shading_scalarRenderer
  Limit arguments of ArrayHandle to to type vtkm::Id
  Fix compile error in debug code due to member name change
  Explicit comparator for moving NO_SUCH_ELEMENT to end of array
  Slice should support slicing along non-zero values
  Switch how InSitu benchmark iterates
  Add support for Offset in ClipWithImplicitFunction
  Update paramter constness to follow vtk-m style in Clip.h
  Fix doxygen groups
  Fix example of gitlab-sync
  ...
This commit is contained in:
Vicente Adolfo Bolea Sanchez 2022-09-27 12:19:48 -04:00
commit d049e27edc
970 changed files with 26591 additions and 18420 deletions

@ -106,7 +106,7 @@
- .docker_image
.ubuntu2004_hip_kokkos: &ubuntu2004_hip_kokkos
image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20210827"
image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20220620"
extends:
- .docker_image
@ -126,9 +126,9 @@
when: on_success
- when: never
.run_master: &run_master
.run_upstream_branches: &run_upstream_branches
rules:
- if: '$CI_PROJECT_PATH == "vtk/vtk-m" && $CI_COMMIT_BRANCH == "master"'
- if: '$CI_PROJECT_PATH == "vtk/vtk-m" && $CI_MERGE_REQUEST_ID == null'
when: on_success
- when: never
@ -164,8 +164,9 @@ stages:
interruptible: true
before_script:
- *install_cmake
- .gitlab/ci/config/sccache.sh
- "cmake -VV -P .gitlab/ci/config/ninja.cmake"
- export PATH=$PWD/.gitlab:$PATH
- .gitlab/ci/config/sccache.sh
- SCCACHE_IDLE_TIMEOUT=0 sccache --start-server
- sccache --show-stats
- .gitlab/ci/config/google_benchmarks.sh
@ -185,6 +186,8 @@ stages:
interruptible: true
before_script:
- *install_cmake
- "cmake -VV -P .gitlab/ci/config/ninja.cmake"
- export PATH=$PWD/.gitlab:$PATH
script:
- "ctest $CTEST_TIMEOUT -VV -S .gitlab/ci/ctest_test.cmake"
extends:
@ -206,9 +209,9 @@ stages:
- build/*.png
- build/*.pnm
- build/*.pmm
- build/junit.xml
reports:
junit:
- build/junit.xml
junit: build/junit.xml
.cmake_build_artifacts: &cmake_build_artifacts
artifacts:
@ -223,17 +226,9 @@ stages:
- build/config/
# CTest and CMake install files.
# XXX(globbing): Can be simplified with support from
# https://gitlab.com/gitlab-org/gitlab-runner/issues/4840
#
# Note: this also captures our CIState.cmake file
- build/CMakeCache.txt
- build/*.cmake
- build/*/*.cmake
- build/*/*/*.cmake
- build/*/*/*/*.cmake
- build/*/*/*/*/*.cmake
- build/*/*/*/*/*/*.cmake
- build/**/*.cmake
- build/Testing/
# CDash files.
@ -245,30 +240,22 @@ stages:
when: always
paths:
# The generated regression testing images
- build/*.png
- build/*.pnm
- build/*.pmm
- build/*/*.png
- build/*/*.pnm
- build/*/*.pmm
- build/*/*/*.png
- build/*/*/*.pnm
- build/*/*/*.pmm
- build/*/*/*/*.png
- build/*/*/*/*.pnm
- build/*/*/*/*.pmm
- build/**/*.png
- build/**/*.pnm
- build/**/*.pmm
- build/junit.xml
reports:
junit:
- build/junit.xml
junit: build/junit.xml
include:
- local: '/.gitlab/ci/ascent.yml'
- local: '/.gitlab/ci/centos7.yml'
- local: '/.gitlab/ci/centos8.yml'
- local: '/.gitlab/ci/doxygen.yml'
- local: '/.gitlab/ci/macos.yml'
- local: '/.gitlab/ci/rhel8.yml'
- local: '/.gitlab/ci/ubuntu1604.yml'
- local: '/.gitlab/ci/ubuntu1804.yml'
- local: '/.gitlab/ci/ubuntu2004.yml'
- local: '/.gitlab/ci/windows10.yml'
- local: '/.gitlab/ci/ascent.yml'

@ -74,14 +74,6 @@ test:ascent_gcc_cuda:
# Tests errors to address due to different env/arch in Ascent
# Refer to issue: https://gitlab.kitware.com/vtk/vtk-m/-/issues/652
CTEST_EXCLUSIONS: >-
UnitTestMathSERIAL
UnitTestMathCUDA
UnitTestSerialDeviceAdapter
UnitTestAverageByKeySERIAL
UnitTestKeysSERIAL
UnitTestWorkletReduceByKeySERIAL
RegressionTestAmrArraysSERIAL
RegressionTestAmrArraysCUDA
before_script:
# Prep the environment

@ -0,0 +1,61 @@
##============================================================================
## 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.
##============================================================================
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
set(version 4.6.1)
set(arch x86_64)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(sha256sum da1e1781bc1c4b019216fa16391af3e1daaee7e7f49a8ec9b0cdc8a1d05c50e2)
set(base_url https://github.com/ccache/ccache/releases/download)
set(platform linux)
set(extension tar.xz)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
set(sha256sum 3e36ba8c80fbf7f2b95fe0227b9dd1ca6143d721aab052caf0d5729769138059)
set(full_url https://gitlab.kitware.com/utils/ci-utilities/-/package_files/534/download)
set(filename ccache)
set(extension tar.gz)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(sha256sum a6c6311973aa3d2aae22424895f2f968e5d661be003b25f1bd854a5c0cd57563)
set(base_url https://github.com/ccache/ccache/releases/download)
set(platform windows)
set(extension zip)
else()
message(FATAL_ERROR "Unrecognized platform ${CMAKE_HOST_SYSTEM_NAME}")
endif()
if(NOT DEFINED filename)
set(filename "ccache-${version}-${platform}-${arch}")
endif()
set(tarball "${filename}.${extension}")
if(NOT DEFINED full_url)
set(full_url "${base_url}/v${version}/${tarball}")
endif()
file(DOWNLOAD
"${full_url}" .gitlab/${tarball}
EXPECTED_HASH SHA256=${sha256sum}
SHOW_PROGRESS
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xf ${tarball}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.gitlab
RESULT_VARIABLE extract_results
)
if(extract_results)
message(FATAL_ERROR "Extracting `${tarball}` failed: ${extract_results}.")
endif()
file(RENAME .gitlab/${filename} .gitlab/ccache)

@ -5,28 +5,27 @@ set -x
version="${1:-3.21.1}"
# We require CMake >= 3.13 in the CI to support CUDA builds
readonly -A linuxParamsByVersion=(
['3.13.5']='e2fd0080a6f0fc1ec84647acdcd8e0b4019770f48d83509e6a5b0b6ea27e5864 Linux'
['3.21.1']='bf496ce869d0aa8c1f57e4d1a2e50c8f2fb12a6cd7ccb37ad743bb88f6b76a1e linux'
)
if [ -z "${linuxParamsByVersion[$version]}" ]
then
echo "Given version ($version) is unsupported"
exit 1
fi
case "$( uname -s )" in
Linux)
shatool="sha256sum"
# We require CMake >= 3.13 in the CI to support CUDA builds
readonly -A linuxParamsByVersion=(
['3.13.5']='e2fd0080a6f0fc1ec84647acdcd8e0b4019770f48d83509e6a5b0b6ea27e5864 Linux'
['3.21.1']='bf496ce869d0aa8c1f57e4d1a2e50c8f2fb12a6cd7ccb37ad743bb88f6b76a1e linux'
)
if [ -z "${linuxParamsByVersion[$version]}" ]
then
echo "Given version ($version) is unsupported"
exit 1
fi
sha256sum=$(cut -f 1 <<<"${linuxParamsByVersion[$version]}")
platform=$(cut -f 2 <<<"${linuxParamsByVersion[$version]}")
arch="x86_64"
;;
Darwin)
shatool="shasum -a 256"
sha256sum="20dbede1d80c1ac80be2966172f8838c3d899951ac4467372f806b386d42ad3c"
sha256sum="9dc2978c4d94a44f71336fa88c15bb0eee47cf44b6ece51b10d1dfae95f82279"
platform="macos"
arch="universal"
;;

@ -101,7 +101,11 @@ foreach(option IN LISTS options)
# From turing we set the architecture using the cannonical
# CMAKE_CUDA_ARCHITECTURES
elseif(turing STREQUAL option)
set(CMAKE_CUDA_ARCHITECTURES "75" CACHE STRING "")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
set(CMAKE_CUDA_ARCHITECTURES "75" CACHE STRING "")
else()
set(VTKm_CUDA_Architecture "turing" CACHE STRING "")
endif()
elseif(hip STREQUAL option)
if(CMAKE_VERSION VERSION_LESS_EQUAL 3.20)
@ -140,6 +144,9 @@ foreach(option IN LISTS options)
if(VTKm_ENABLE_CUDA)
set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_COMMAND}" CACHE STRING "")
endif()
if(VTKm_ENABLE_KOKKOS_HIP)
set(CMAKE_HIP_COMPILER_LAUNCHER "${CCACHE_COMMAND}" CACHE STRING "")
endif()
else()
message(FATAL_ERROR "CCACHE version [${CCACHE_VERSION}] is <= 4")
endif()
@ -161,10 +168,6 @@ if(SCCACHE_COMMAND)
set(CMAKE_C_COMPILER_LAUNCHER "${SCCACHE_COMMAND}" CACHE STRING "")
set(CMAKE_CXX_COMPILER_LAUNCHER "${SCCACHE_COMMAND}" CACHE STRING "")
if(DEFINED VTKm_ENABLE_KOKKOS_HIP)
set(CMAKE_HIP_COMPILER_LAUNCHER "${SCCACHE_COMMAND}" CACHE STRING "")
endif()
# Use VTKm_CUDA_Architecture to determine if we need CUDA sccache setup
# since this will also capture when kokkos is being used with CUDA backing
if(DEFINED VTKm_CUDA_Architecture OR DEFINED CMAKE_CUDA_ARCHITECTURES)

@ -0,0 +1,44 @@
##============================================================================
## 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.
##============================================================================
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
set(version 1.11.0)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(sha256sum 9726e730d5b8599f82654dc80265e64a10a8a817552c34153361ed0c017f9f02)
set(platform linux)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
set(sha256sum 21915277db59756bfc61f6f281c1f5e3897760b63776fd3d360f77dd7364137f)
set(platform mac)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(sha256sum d0ee3da143211aa447e750085876c9b9d7bcdd637ab5b2c5b41349c617f22f3b)
set(platform win)
else()
message(FATAL_ERROR "Unrecognized platform ${CMAKE_HOST_SYSTEM_NAME}")
endif()
set(tarball "ninja-${platform}.zip")
file(DOWNLOAD
"https://github.com/ninja-build/ninja/releases/download/v${version}/${tarball}" .gitlab/${tarball}
EXPECTED_HASH SHA256=${sha256sum}
SHOW_PROGRESS
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xf ${tarball}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.gitlab
RESULT_VARIABLE extract_results
)
if(extract_results)
message(FATAL_ERROR "Extracting `${tarball}` failed: ${extract_results}.")
endif()

@ -42,12 +42,18 @@ if (test_exclusions)
set(test_exclusions "(${test_exclusions})")
endif ()
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
set(junit_args OUTPUT_JUNIT "${CTEST_BINARY_DIRECTORY}/junit.xml")
endif()
# reduced parallel level so we don't exhaust system resources
ctest_memcheck(
PARALLEL_LEVEL "4"
RETURN_VALUE test_result
EXCLUDE "${test_exclusions}"
DEFECT_COUNT defects)
DEFECT_COUNT defects
${junit_args}
)
ctest_submit(PARTS Memcheck BUILD_ID build_id)
message(STATUS "Memcheck submission build_id: ${build_id}")

@ -32,7 +32,7 @@ if (test_exclusions)
set(test_exclusions "(${test_exclusions})")
endif ()
if (CMAKE_VERSION VERSION_GREATER 3.21.0)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
set(junit_args OUTPUT_JUNIT "${CTEST_BINARY_DIRECTORY}/junit.xml")
endif()

@ -2,24 +2,35 @@ FROM rocm/dev-ubuntu-20.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@kitware.com>"
# Base dependencies for building VTK-m projects
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
cmake \
curl \
g++ \
git \
git-lfs \
libmpich-dev \
libomp-dev \
mpich \
ninja-build \
rsync \
ssh \
software-properties-common
RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
curl \
g++ \
git \
git-lfs \
libmpich-dev \
libomp-dev \
mpich \
ninja-build \
rsync \
ssh \
&& \
apt clean
# Need to run git-lfs install manually on ubuntu based images when using the
# system packaged version
RUN git-lfs install
# Provide CCACHE
ENV CCACHE_DIR "/ccache"
ENV PATH "/opt/ccache/bin:${PATH}"
ARG CCACHE_VERSION=4.6.1
RUN mkdir /opt/ccache/ && \
curl -L https://github.com/ccache/ccache/releases/download/v$CCACHE_VERSION/ccache-$CCACHE_VERSION-linux-x86_64.tar.xz | tar -vxJ && \
make -C ccache-$CCACHE_VERSION-linux-x86_64 install prefix=/opt/ccache && \
rm -rf ccache-$CCACHE_VERSION-linux-x86_64 && \
ccache -z && ccache -s
# Provide CMake
ARG CMAKE_VERSION=3.21.1
RUN mkdir /opt/cmake/ && \
@ -33,11 +44,10 @@ ENV CMAKE_PREFIX_PATH "/opt/rocm/lib/cmake:/opt/rocm/lib:${CMAKE_PREFIX_PATH}"
ENV CMAKE_GENERATOR "Ninja"
# Build and install Kokkos
ARG KOKKOS_VERSION=3.4.01
ARG KOKKOS_VERSION=3.6.00
COPY kokkos_cmake_config.cmake kokkos_cmake_config.cmake
RUN curl -L https://github.com/kokkos/kokkos/archive/refs/tags/$KOKKOS_VERSION.tar.gz | tar -xzf - && \
cmake -S kokkos-$KOKKOS_VERSION -B build -C kokkos_cmake_config.cmake && \
cmake --build build -v && \
sudo cmake --install build
RUN rm -rf build
cmake -S kokkos-$KOKKOS_VERSION -B build -C kokkos_cmake_config.cmake && \
cmake --build build -v && \
cmake --install build && \
rm -rf build kokkos-$KOKKOS_VERSION

83
.gitlab/ci/macos.yml Normal file

@ -0,0 +1,83 @@
# Ad-hoc build that runs in macos machines
build:macos_xcode13:
extends:
- .macos_xcode13
- .macos_build_tags
- .cmake_build_macos
- .run_automatically
test:macos_xcode13:
extends:
- .macos_xcode13
- .macos_build_tags
- .cmake_test_macos
- .run_automatically
needs:
- build:macos_xcode13
dependencies:
- build:macos_xcode13
.macos_xcode13:
variables:
CMAKE_BUILD_TYPE: RelWithDebInfo
CMAKE_GENERATOR: Ninja
CC: gcc
CXX: g++
DEVELOPER_DIR: "/Applications/Xcode-13.3.app/Contents/Developer"
VTKM_SETTINGS: "64bit_floats+shared+ccache"
.cmake_build_macos:
stage: build
interruptible: true
variables:
CCACHE_BASEDIR: "$CI_PROJECT_DIR"
CCACHE_DIR: "$CI_PROJECT_DIR/ccache"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_COMPILERCHECK: "content"
CCACHE_NOHASHDIR: "true"
CCACHE_RESHARE: "true"
before_script:
- .gitlab/ci/config/cmake.sh
- export PATH=$PWD/.gitlab/cmake/bin:$PATH
- "cmake -VV -P .gitlab/ci/config/ccache.cmake"
- export PATH=$PWD/.gitlab/ccache:$PATH
- "cmake -VV -P .gitlab/ci/config/ninja.cmake"
- export PATH=$PWD/.gitlab:$PATH
- "cmake --version"
- "ccache --version"
- "ninja --version"
- "cmake -V -P .gitlab/ci/config/fetch_vtkm_tags.cmake"
- "cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake"
- "ctest -VV -S .gitlab/ci/ctest_configure.cmake"
script:
- "ctest -VV -S .gitlab/ci/ctest_build.cmake"
after_script:
- ccache -v -s
- ccache -z
extends:
- .cmake_build_artifacts
.cmake_test_macos:
stage: test
interruptible: true
before_script:
- .gitlab/ci/config/cmake.sh
- export PATH=.gitlab/cmake/bin:$PATH
- "cmake -VV -P .gitlab/ci/config/ninja.cmake"
- export PATH=$PWD/.gitlab:$PATH
- cmake --version
- ninja --version
script:
- "ctest $CTEST_TIMEOUT -VV -S .gitlab/ci/ctest_test.cmake"
extends:
- .cmake_test_artifacts
.macos_build_tags:
tags:
- vtk-m
- macos
- xcode-13.3
- nonconcurrent

@ -50,7 +50,7 @@ build:ubuntu1604_gcc5_2:
extends:
- .ubuntu1604_cuda
- .cmake_build_linux
- .run_master
- .run_upstream_branches
- .use_minimum_supported_cmake
variables:
CC: "gcc-5"
@ -69,7 +69,7 @@ test:ubuntu1804_test_ubuntu1604_gcc5_2:
extends:
- .ubuntu1804_cuda
- .cmake_test_linux
- .run_master
- .run_upstream_branches
variables:
CTEST_EXCLUSIONS: "built_against_test_install"
dependencies:

@ -91,7 +91,7 @@ build:ubuntu1804_clang_cuda:
- .ubuntu1804_cuda
- .cmake_build_linux
- .run_automatically
# - .run_master
# - .run_upstream_branches
variables:
CC: "clang-8"
CXX: "clang++-8"
@ -110,7 +110,7 @@ test:ubuntu1804_clang_cuda:
- .ubuntu1804_cuda
- .cmake_test_linux
- .run_automatically
# - .run_master
# - .run_upstream_branches
dependencies:
- build:ubuntu1804_clang_cuda
needs:

@ -69,13 +69,23 @@ build:ubuntu2004_hip_kokkos:
extends:
- .ubuntu2004_hip_kokkos
- .cmake_build_linux
- .run_scheduled
- .run_upstream_branches
variables:
CMAKE_BUILD_TYPE: RelWithDebInfo
VTKM_SETTINGS: "benchmarks+kokkos+hip+no_virtual+no_rendering"
VTKM_SETTINGS: "benchmarks+kokkos+hip+no_virtual+no_rendering+ccache"
CMAKE_PREFIX_PATH: "/opt/rocm/lib/cmake"
CTEST_MAX_PARALLELISM: "1"
timeout: 12 hours
CCACHE_BASEDIR: "$CI_PROJECT_DIR"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_COMPILERCHECK: "content"
CCACHE_NOHASHDIR: "true"
CCACHE_RESHARE: "true"
after_script:
- ccache -v -s
- ccache -z
timeout: 10 hours
test:ubuntu2004_hip_kokkos:
tags:
@ -86,7 +96,7 @@ test:ubuntu2004_hip_kokkos:
extends:
- .ubuntu2004_hip_kokkos
- .cmake_test_linux
- .run_scheduled
- .run_upstream_branches
variables:
CTEST_TIMEOUT: "30"
dependencies:

@ -29,8 +29,12 @@
- Invoke-Expression -Command .gitlab/ci/config/cmake.ps1
- Invoke-Expression -Command .gitlab/ci/config/vcvarsall.ps1
- $pwdpath = $pwd.Path
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$pwdpath\.gitlab\cmake\bin;$env:PATH"
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\cmake\bin;$env:PATH"
- "cmake --version"
- "cmake -V -P .gitlab/ci/config/ccache.cmake"
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\ccache;$env:PATH"
- "cmake -V -P .gitlab/ci/config/ninja.cmake"
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$env:PATH"
- "cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake"
- "ctest -VV -S .gitlab/ci/ctest_configure.cmake"
script:
@ -47,17 +51,9 @@
- build/config/
# CTest and CMake install files.
# XXX(globbing): Can be simplified with support from
# https://gitlab.com/gitlab-org/gitlab-runner/issues/4840
#
# Note: this also captures our CIState.cmake file
- build/CMakeCache.txt
- build/*.cmake
- build/*/*.cmake
- build/*/*/*.cmake
- build/*/*/*/*.cmake
- build/*/*/*/*/*.cmake
- build/*/*/*/*/*/*.cmake
- build/**/*.cmake
- build/Testing/
# CDash files.
@ -75,7 +71,10 @@
- Invoke-Expression -Command .gitlab/ci/config/cmake.ps1
- Invoke-Expression -Command .gitlab/ci/config/vcvarsall.ps1
- $pwdpath = $pwd.Path
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$pwdpath\.gitlab\cmake\bin;$env:PATH"
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\cmake\bin;$env:PATH"
- "cmake --version"
- "cmake -V -P .gitlab/ci/config/ninja.cmake"
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$env:PATH"
script:
- "ctest -VV -S .gitlab/ci/ctest_test.cmake"

@ -21,46 +21,64 @@ git submodule update --recursive --init
## Create update branch
- [ ] Create update branch `git checkout -b update-to-v@VERSION@`
<!-- if @RC@ == "-rc1"
<!-- if @RC@ == "-rc1"-->
- [ ] Bring as a second parent the history of master (Solve conflicts always
taking master's version)
```
git merge --no-ff origin/master
```
-->
<!-- endif -->
<!-- Do we have new release notes?
<!-- if not a patch release -->
- [ ] Update the major and minor version in `version.txt`:
```
echo "@MAJOR@.@MINOR@.9999" > version.txt
git add version.txt`
```
<!-- endif -->
- [ ] Update the version (not in patch releases) and date in the LICENSE.md
file `git add LICENSE.md`.
- [ ] Create commit that updates the License (and version.txt if modified):
```
git commit -m 'release: update version and License'
```
<!-- Do we have new release notes? -->
- [ ] Craft or update [changelog](#generate-change-log)
`docs/changelog/@VERSION@/release-notes.md` file.
- [ ] Create release notes commit.
```
git add docs/changelog/@VERSION@/release-notes.md
git rm docs/changelog/*.md
git commit -m 'Add release notes for @VERSION@@RC@'
git commit -m 'release: @VERSION@@RC@ release notes'
```
-->
- [ ] Update the version (not in patch releases) and date in the LICENSE.md
file.
<!-- endif -->
- [ ] Create update version commit:
```
# Create branch
git checkout -b update-to-v@VERSION@@RC@
echo @VERSION@@RC@ > version.txt
git add version.txt
# Create commit with the following template
# Nth is counted by the number of tags
# Nth is counted by the number of final release tags
git commit -m '@VERSION@@RC@ is our Nth official release of VTK-m.
The major changes to VTK-m from (previous release) can be found in:
docs/changelog/@VERSION@/release-notes.md' version.txt'
docs/changelog/@VERSION@/release-notes.md' version.txt
```
- [ ] `git tag -a -m 'VTKm @VERSION@@RC@' v@VERSION@@RC@ HEAD`
- Integrate changes to `release` branch
- [ ] Create a MR using the [release-mr script][1]
(see [notes](#notes-about-update-mr)).
<!-- if not patch release -->
- [ ] Add (or ensure) at the bottom of the description of the merge request:
`Backport: master:HEAD~1`
<!-- elseif patch release -->
- [ ] Remove (or ensure) that at the bottom of the description of the merge
request there is no `Backport` instruction.
<!-- endif -->
- [ ] Get +1
- [ ] `Do: merge`
- Push tags
@ -76,10 +94,14 @@ The major changes to VTK-m from (previous release) can be found in:
- [ ] Tag new version of the [VTK-m User Guide][2].
<!-- endif -->
- [ ] Post an [Email Announcements](#email-announcements) VTK-m mailing list.
<!-- if not patch release -->
- [ ] Ensure that the content of `version.txt` in master is
`[@MAJOR@ @MINOR@](@MAJOR@.@MINOR@.9999)`.
<!-- endif release -->
---
# Annex
# Annex
## Generate change log
Construct a `docs/changelog/@VERSION@/` folder.
@ -157,6 +179,16 @@ to the relevant `release-notes` section.
Lastly, `update-mr` can be used multiple times with different commit in the same
branch.
## Notes about version.txt
Master and release branch do not share the same version.txt scheme. In the
release branch the patch and release-candidate version is observed whereas in
master the patch field is fixed to _9999_ indicating that each of its commit is
a developing release.
- Master: `@MAJOR@.@MINOR@.9999`
- Release: `@MAJOR@.@MINOR@.@PATCH@@RC@`
## Email Announcements
Announce the new VTK-m release on the mailing list. You will need to compute

@ -114,6 +114,8 @@ function(do_verify root_dir prefix)
set(file_exceptions
thirdparty/diy/vtkmdiy/cmake/mpi_types.h
thirdparty/lodepng/vtkmlodepng/lodepng.h
thirdparty/loguru/vtkmloguru/loguru.hpp
# Ignore deprecated virtual classes (which are not installed if VTKm_NO_DEPRECATED_VIRTUAL
# is on). These exceptions can be removed when these files are completely removed.

@ -13,11 +13,11 @@ include(VTKmWrappers)
function(vtkm_create_test_executable
prog_name
sources
device_sources
libraries
defines
is_mpi_test
use_mpi
enable_all_backends
use_job_pool)
vtkm_diy_use_mpi_push()
@ -41,23 +41,12 @@ function(vtkm_create_test_executable
#the creation of the test source list needs to occur before the labeling as
#cuda. This is so that we get the correctly named entry points generated
create_test_sourcelist(test_sources ${prog}.cxx ${sources} ${extraArgs})
create_test_sourcelist(test_sources ${prog}.cxx ${sources} ${device_sources} ${extraArgs})
add_executable(${prog} ${prog}.cxx ${sources})
add_executable(${prog} ${test_sources})
vtkm_add_drop_unused_function_flags(${prog})
target_compile_definitions(${prog} PRIVATE ${defines})
#determine if we have a device that requires a separate compiler enabled
set(device_lang_enabled FALSE)
if( (TARGET vtkm::cuda) OR (TARGET vtkm::kokkos_cuda) OR (TARGET vtkm::kokkos_hip))
set(device_lang_enabled TRUE)
endif()
#if all backends are enabled, we can use the device compiler to handle all possible backends.
set(device_sources)
if(device_lang_enabled AND (enable_all_backends OR (TARGET vtkm::kokkos_hip)))
set(device_sources ${sources})
endif()
vtkm_add_target_information(${prog} DEVICE_SOURCES ${device_sources})
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
@ -83,68 +72,89 @@ endfunction()
# (package, module, whatever you call it). Usage:
#
# vtkm_unit_tests(
# NAME
# [ NAME <name> ]
# SOURCES <source_list>
# LIBRARIES <dependent_library_list>
# DEFINES <target_compile_definitions>
# TEST_ARGS <argument_list>
# MPI
# ALL_BACKENDS
# USE_VTKM_JOB_POOL
# <options>
# [ DEVICE_SOURCES <source_list> ]
# [ LIBRARIES <dependent_library_list> ]
# [ DEFINES <target_compile_definitions> ]
# [ TEST_ARGS <argument_list> ]
# [ MPI ]
# [ BACKEND <device> ]
# [ ALL_BACKENDS ]
# [ USE_VTKM_JOB_POOL ]
# )
#
# [LIBRARIES] : extra libraries that this set of tests need to link too
# NAME : Specify the name of the testing executable. If not specified,
# UnitTests_<kitname> is used.
#
# [DEFINES] : extra defines that need to be set for all unit test sources
# SOURCES: A list of the source files. Each file is expected to contain a
# function with the same name as the source file. For example, if SOURCES
# contains `UnitTestFoo.cxx`, then `UnitTestFoo.cxx` should contain a
# function named `UnitTestFoo`. A test with this name is also added to ctest.
#
# [LABEL] : CTest Label to associate to this set of tests
# LIBRARIES: Extra libraries that this set of tests need to link to.
#
# [TEST_ARGS] : arguments that should be passed on the command line to the
# test executable
# DEFINES: Extra defines to be set for all unit test sources.
#
# [MPI] : when specified, the tests should be run in parallel if
# MPI is enabled. The tests should also be able to build and run
# When MPI is not available, i.e., they should not make explicit
# use of MPI and instead completely rely on DIY.
# [ALL_BACKENDS] : when specified, the tests would test against all enabled
# backends. Otherwise we expect the tests to manage the
# backends at runtime.
# TEST_ARGS: Arguments that should be passed on the command line to the
# test executable when executed by ctest.
#
# MPI: When specified, the tests should be run in parallel if MPI is enabled.
# The tests should also be able to build and run when MPI is not available,
# i.e., they should not make explicit use of MPI and instead completely rely
# on DIY.
#
# BACKEND: When used, a specific backend will be forced for the device.
# A `--vtkm-device` flag will be given to the command line argument with the
# specified device. When not used, a backend will be chosen.
#
# ALL_BACKENDS: When used, a separate ctest test is created for each device
# that VTK-m is compiled for. The call will add the `--vtkm-device` flag when
# running the test to force the test for a particular backend.
#
function(vtkm_unit_tests)
set(options)
set(global_options ${options} USE_VTKM_JOB_POOL MPI ALL_BACKENDS)
set(oneValueArgs BACKEND NAME LABEL)
set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
set(multiValueArgs SOURCES DEVICE_SOURCES LIBRARIES DEFINES TEST_ARGS)
cmake_parse_arguments(VTKm_UT
"${global_options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES})
set(per_device_command_line_arguments "NONE")
set(per_device_suffix "")
set(per_device_timeout 180)
set(per_device_serial FALSE)
set(per_device_command_line_arguments)
set(per_device_suffix)
set(per_device_timeout)
set(per_device_serial)
set(enable_all_backends ${VTKm_UT_ALL_BACKENDS})
if(enable_all_backends)
set(per_device_command_line_arguments --vtkm-device=serial)
set(per_device_suffix "SERIAL")
if (VTKm_ENABLE_CUDA)
if(NOT VTKm_UT_BACKEND)
set(enable_all_backends ${VTKm_UT_ALL_BACKENDS})
# If ALL_BACKENDS is specified, add a test for each backend. If it is not
# specified, pick a backend to use. Pick the most "specific" backend so
# that different CI builds will use different backends. This ensures that
# we do not have a test that always drops down to serial.
if(VTKm_ENABLE_CUDA AND (enable_all_backends OR NOT per_device_suffix))
list(APPEND per_device_command_line_arguments --vtkm-device=cuda)
list(APPEND per_device_suffix "CUDA")
#CUDA tests generally require more time because of kernel generation.
list(APPEND per_device_timeout 1500)
list(APPEND per_device_serial FALSE)
endif()
if (VTKm_ENABLE_TBB)
if(VTKm_ENABLE_KOKKOS AND (enable_all_backends OR NOT per_device_suffix))
list(APPEND per_device_command_line_arguments --vtkm-device=kokkos)
list(APPEND per_device_suffix "KOKKOS")
#may require more time because of kernel generation.
list(APPEND per_device_timeout 1500)
list(APPEND per_device_serial FALSE)
endif()
if(VTKm_ENABLE_TBB AND (enable_all_backends OR NOT per_device_suffix))
list(APPEND per_device_command_line_arguments --vtkm-device=tbb)
list(APPEND per_device_suffix "TBB")
list(APPEND per_device_timeout 180)
list(APPEND per_device_serial FALSE)
endif()
if (VTKm_ENABLE_OPENMP)
if(VTKm_ENABLE_OPENMP AND (enable_all_backends OR NOT per_device_suffix))
list(APPEND per_device_command_line_arguments --vtkm-device=openmp)
list(APPEND per_device_suffix "OPENMP")
list(APPEND per_device_timeout 180)
@ -154,13 +164,26 @@ function(vtkm_unit_tests)
#serially
list(APPEND per_device_serial TRUE)
endif()
if (VTKm_ENABLE_KOKKOS)
list(APPEND per_device_command_line_arguments --vtkm-device=kokkos)
list(APPEND per_device_suffix "KOKKOS")
#may require more time because of kernel generation.
list(APPEND per_device_timeout 1500)
if(enable_all_backends OR NOT per_device_suffix)
list(APPEND per_device_command_line_arguments --vtkm-device=serial)
list(APPEND per_device_suffix "SERIAL")
list(APPEND per_device_timeout 180)
list(APPEND per_device_serial FALSE)
endif()
if(NOT enable_all_backends)
# If not enabling all backends, exactly one backend should have been added.
list(LENGTH per_device_suffix number_of_devices)
if(NOT number_of_devices EQUAL 1)
message(FATAL_ERROR "Expected to pick one backend")
endif()
endif()
else()
# A specific backend was requested.
set(per_device_command_line_arguments --vtkm-device=${VTKm_UT_BACKEND})
set(per_device_suffix ${VTKm_UT_BACKEND})
set(per_device_timeout 180)
# Some devices don't like multiple tests run at the same time.
set(per_device_serial TRUE)
endif()
set(test_prog)
@ -188,33 +211,33 @@ function(vtkm_unit_tests)
vtkm_create_test_executable(
${test_prog}
"${VTKm_UT_SOURCES}"
"${VTKm_UT_DEVICE_SOURCES}"
"${VTKm_UT_LIBRARIES}"
"${VTKm_UT_DEFINES}"
ON # is_mpi_test
ON # use_mpi
${enable_all_backends}
${VTKm_UT_USE_VTKM_JOB_POOL})
endif()
if ((NOT VTKm_ENABLE_MPI) OR VTKm_ENABLE_DIY_NOMPI)
vtkm_create_test_executable(
${test_prog}
"${VTKm_UT_SOURCES}"
"${VTKm_UT_DEVICE_SOURCES}"
"${VTKm_UT_LIBRARIES}"
"${VTKm_UT_DEFINES}"
ON # is_mpi_test
OFF # use_mpi
${enable_all_backends}
${VTKm_UT_USE_VTKM_JOB_POOL})
endif()
else()
vtkm_create_test_executable(
${test_prog}
"${VTKm_UT_SOURCES}"
"${VTKm_UT_DEVICE_SOURCES}"
"${VTKm_UT_LIBRARIES}"
"${VTKm_UT_DEFINES}"
OFF # is_mpi_test
OFF # use_mpi
${enable_all_backends}
${VTKm_UT_USE_VTKM_JOB_POOL})
endif()
@ -225,19 +248,16 @@ function(vtkm_unit_tests)
#exclusive on the end ( e.g. for(i=0; i < n; ++i))
break()
endif()
if(per_device_command_line_arguments STREQUAL "NONE")
set(device_command_line_argument)
set(upper_backend ${per_device_suffix})
set(timeout ${per_device_timeout})
set(run_serial ${per_device_serial})
else()
list(GET per_device_command_line_arguments ${index} device_command_line_argument)
if(enable_all_backends)
list(GET per_device_suffix ${index} upper_backend)
list(GET per_device_timeout ${index} timeout)
list(GET per_device_serial ${index} run_serial)
else()
set(upper_backend)
endif()
list(GET per_device_command_line_arguments ${index} device_command_line_argument)
list(GET per_device_timeout ${index} timeout)
list(GET per_device_serial ${index} run_serial)
foreach (test ${VTKm_UT_SOURCES})
foreach (test ${VTKm_UT_SOURCES} ${VTKm_UT_DEVICE_SOURCES})
get_filename_component(tname ${test} NAME_WE)
if(VTKm_UT_MPI)
if (VTKm_ENABLE_MPI)

@ -413,7 +413,7 @@ extend or revise the topic.
2. Get the new version from gitlab
$ git gitlab-sync -f
$ git gitlab-sync
If you do not wish to have the "Kitware Robot" automatically reformat your

@ -29,7 +29,6 @@
#include <vtkm/cont/internal/OptionParser.h>
#include <vtkm/filter/FieldSelection.h>
#include <vtkm/filter/PolicyBase.h>
#include <vtkm/filter/contour/Contour.h>
#include <vtkm/filter/entity_extraction/ExternalFaces.h>
#include <vtkm/filter/entity_extraction/Threshold.h>

@ -10,11 +10,16 @@
#include "Benchmarker.h"
#include <cstddef>
#include <random>
#include <sstream>
#include <unordered_map>
#include <vtkm/ImplicitFunction.h>
#include <vtkm/Particle.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/BoundsCompute.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/FieldRangeCompute.h>
@ -25,9 +30,9 @@
#include <vtkm/cont/internal/OptionParser.h>
#include <vtkm/filter/Streamline.h>
#include <vtkm/filter/contour/Contour.h>
#include <vtkm/filter/contour/Slice.h>
#include <vtkm/filter/flow/Streamline.h>
#include <vtkm/filter/geometry_refinement/Tetrahedralize.h>
#include <vtkm/filter/geometry_refinement/Tube.h>
#include <vtkm/filter/vector_analysis/Gradient.h>
@ -45,7 +50,6 @@
namespace
{
const uint32_t DEFAULT_NUM_CYCLES = 20;
const vtkm::Id DEFAULT_DATASET_DIM = 128;
const vtkm::Id DEFAULT_IMAGE_SIZE = 1024;
@ -63,6 +67,29 @@ std::string PointScalarsName;
// The point vectors to use:
std::string PointVectorsName;
// Global counters for number of cycles
// These are globals because google benchmarks restarts the test for every
// repetition when using --benchmark_repetitions
// Additionlly, we need this global flag for when not doing repetitions,
// as benchmark will repeatedly drop in and out of the measured function
// and report the number of iterations for the last run of the function.
// Thus, we'll have way more output images than what the iteration number
// would lead you to believe (maybe fixed in > 1.7 with warmup time specifier)
bool benchmark_repetitions = false;
inline void hash_combine(std::size_t& vtkmNotUsed(seed)) {}
template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
hash_combine(seed, rest...);
}
std::unordered_map<size_t, int> bench_cycles;
enum class RenderingMode
{
None = 0,
@ -282,33 +309,43 @@ void BenchContour(::benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
const vtkm::Id numIsoVals = static_cast<vtkm::Id>(state.range(1));
const bool isStructured = static_cast<bool>(state.range(2));
const bool isMultiBlock = static_cast<bool>(state.range(3));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(4));
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
vtkm::filter::contour::Contour filter;
filter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::Points);
filter.SetMergeDuplicatePoints(true);
filter.SetGenerateNormals(true);
filter.SetComputeFastNormalsForStructured(true);
filter.SetComputeFastNormalsForUnstructured(true);
const vtkm::Id numIsoVals = static_cast<vtkm::Id>(state.range(0));
const bool isStructured = static_cast<bool>(state.range(1));
const bool isMultiBlock = static_cast<bool>(state.range(2));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(3));
vtkm::cont::Timer totalTimer{ device };
vtkm::cont::Timer filterTimer{ device };
vtkm::cont::Timer renderTimer{ device };
vtkm::cont::Timer writeTimer{ device };
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchContour"), isStructured, isMultiBlock, renderAlgo);
int* cycles = &(bench_cycles[hash_val]);
if (!benchmark_repetitions)
*cycles = 0;
for (auto _ : state)
{
(void)_;
totalTimer.Start();
// Disable the benchmark timers for the updating/creation of the datasets
state.PauseTiming(); // Stop timers.
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(*cycles, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
vtkm::filter::contour::Contour filter;
filter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::Points);
filter.SetMergeDuplicatePoints(true);
filter.SetGenerateNormals(true);
filter.SetComputeFastNormalsForStructured(true);
filter.SetComputeFastNormalsForUnstructured(true);
state.ResumeTiming(); // And resume timers.
filterTimer.Start();
std::vector<vtkm::cont::DataSet> dataSets;
if (isMultiBlock)
@ -330,11 +367,13 @@ void BenchContour(::benchmark::State& state)
renderTimer.Stop();
writeTimer.Start();
WriteToDisk(*canvas, renderAlgo, "contour", isStructured, isMultiBlock, cycle);
WriteToDisk(*canvas, renderAlgo, "contour", isStructured, isMultiBlock, *cycles);
writeTimer.Stop();
totalTimer.Stop();
(*cycles)++;
state.SetIterationTime(totalTimer.GetElapsedTime());
state.counters.insert(
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
@ -346,21 +385,24 @@ void BenchContour(::benchmark::State& state)
void BenchContourGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "Cycle", "NIsos", "IsStructured", "IsMultiBlock", "RenderingMode" });
bm->ArgNames({ "NIsos", "IsStructured", "IsMultiBlock", "RenderingMode" });
std::vector<uint32_t> isStructureds{ false, true };
std::vector<uint32_t> isMultiBlocks{ false, true };
std::vector<RenderingMode> renderingModes{ RenderingMode::RayTrace };
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
for (auto& isStructured : isStructureds)
{
for (auto& isStructured : isStructureds)
for (auto& isMultiBlock : isMultiBlocks)
{
for (auto& isMultiBlock : isMultiBlocks)
for (auto& mode : renderingModes)
{
for (auto& mode : renderingModes)
{
bm->Args({ cycle, 10, isStructured, isMultiBlock, static_cast<int>(mode) });
}
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchContour"), isStructured, isMultiBlock, mode);
auto search = bench_cycles.find(hash_val);
// If we can't find the hash, or we're not doing repetitions, reset to 0
if (search == bench_cycles.end())
bench_cycles[hash_val] = 0;
bm->Args({ 10, isStructured, isMultiBlock, static_cast<int>(mode) });
}
}
}
@ -423,7 +465,7 @@ void AddField(vtkm::cont::PartitionedDataSet& input,
}
template <typename DataSetType>
DataSetType RunStreamlinesHelper(vtkm::filter::Streamline& filter, const DataSetType& input)
DataSetType RunStreamlinesHelper(vtkm::filter::flow::Streamline& filter, const DataSetType& input)
{
auto dataSetBounds = vtkm::cont::BoundsCompute(input);
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
@ -447,30 +489,40 @@ void BenchStreamlines(::benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
const bool isStructured = static_cast<bool>(state.range(1));
const bool isMultiBlock = static_cast<bool>(state.range(2));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(3));
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
vtkm::filter::Streamline streamline;
streamline.SetStepSize(0.1f);
streamline.SetNumberOfSteps(1000);
streamline.SetActiveField(PointVectorsName);
const bool isStructured = static_cast<bool>(state.range(0));
const bool isMultiBlock = static_cast<bool>(state.range(1));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(2));
vtkm::cont::Timer totalTimer{ device };
vtkm::cont::Timer filterTimer{ device };
vtkm::cont::Timer renderTimer{ device };
vtkm::cont::Timer writeTimer{ device };
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchStreamlines"), isStructured, isMultiBlock, renderAlgo);
int* cycles = &(bench_cycles[hash_val]);
if (!benchmark_repetitions)
*cycles = 0;
for (auto _ : state)
{
(void)_;
totalTimer.Start();
// Disable the benchmark timers for the updating/creation of the datasets
state.PauseTiming(); // Stop timers.
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(*cycles, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
vtkm::filter::flow::Streamline streamline;
streamline.SetStepSize(0.1f);
streamline.SetNumberOfSteps(1000);
streamline.SetActiveField(PointVectorsName);
state.ResumeTiming(); // And resume timers.
filterTimer.Start();
std::vector<vtkm::cont::DataSet> dataSets;
@ -493,11 +545,13 @@ void BenchStreamlines(::benchmark::State& state)
renderTimer.Stop();
writeTimer.Start();
WriteToDisk(*canvas, renderAlgo, "streamlines", isStructured, isMultiBlock, cycle);
WriteToDisk(*canvas, renderAlgo, "streamlines", isStructured, isMultiBlock, *cycles);
writeTimer.Stop();
totalTimer.Stop();
(*cycles)++;
state.SetIterationTime(totalTimer.GetElapsedTime());
state.counters.insert(
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
@ -509,21 +563,24 @@ void BenchStreamlines(::benchmark::State& state)
void BenchStreamlinesGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" });
bm->ArgNames({ "IsStructured", "IsMultiBlock", "RenderingMode" });
std::vector<uint32_t> isStructureds{ false, true };
std::vector<uint32_t> isMultiBlocks{ false, true };
std::vector<RenderingMode> renderingModes{ RenderingMode::Mesh };
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
for (auto& isStructured : isStructureds)
{
for (auto& isStructured : isStructureds)
for (auto& isMultiBlock : isMultiBlocks)
{
for (auto& isMultiBlock : isMultiBlocks)
for (auto& mode : renderingModes)
{
for (auto& mode : renderingModes)
{
bm->Args({ cycle, isStructured, isMultiBlock, static_cast<int>(mode) });
}
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchStreamlines"), isStructured, isMultiBlock, mode);
auto search = bench_cycles.find(hash_val);
// If we can't find the hash, or we're not doing repetitions, reset to 0
if (search == bench_cycles.end())
bench_cycles[hash_val] = 0;
bm->Args({ isStructured, isMultiBlock, static_cast<int>(mode) });
}
}
}
@ -567,15 +624,9 @@ void BenchSlice(::benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
const bool isStructured = static_cast<bool>(state.range(1));
const bool isMultiBlock = static_cast<bool>(state.range(2));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(3));
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
const bool isStructured = static_cast<bool>(state.range(0));
const bool isMultiBlock = static_cast<bool>(state.range(1));
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(2));
vtkm::filter::contour::Slice filter;
@ -584,10 +635,26 @@ void BenchSlice(::benchmark::State& state)
vtkm::cont::Timer renderTimer{ device };
vtkm::cont::Timer writeTimer{ device };
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchSlice"), isStructured, isMultiBlock, renderAlgo);
int* cycles = &(bench_cycles[hash_val]);
if (!benchmark_repetitions)
*cycles = 0;
for (auto _ : state)
{
(void)_;
totalTimer.Start();
// Disable the benchmark timers for the updating/creation of the datasets
state.PauseTiming(); // Stop timers.
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(*cycles, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
state.ResumeTiming(); // And resume timers.
filterTimer.Start();
std::vector<vtkm::cont::DataSet> dataSets;
if (isMultiBlock)
@ -617,11 +684,13 @@ void BenchSlice(::benchmark::State& state)
renderTimer.Stop();
writeTimer.Start();
WriteToDisk(*canvas, renderAlgo, "slice", isStructured, isMultiBlock, cycle);
WriteToDisk(*canvas, renderAlgo, "slice", isStructured, isMultiBlock, *cycles);
writeTimer.Stop();
totalTimer.Stop();
(*cycles)++;
state.SetIterationTime(totalTimer.GetElapsedTime());
state.counters.insert(
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
@ -633,21 +702,24 @@ void BenchSlice(::benchmark::State& state)
void BenchSliceGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" });
bm->ArgNames({ "IsStructured", "IsMultiBlock", "RenderingMode" });
std::vector<uint32_t> isStructureds{ false, true };
std::vector<uint32_t> isMultiBlocks{ false, true };
std::vector<RenderingMode> renderingModes{ RenderingMode::RayTrace };
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
for (auto& isStructured : isStructureds)
{
for (auto& isStructured : isStructureds)
for (auto& isMultiBlock : isMultiBlocks)
{
for (auto& isMultiBlock : isMultiBlocks)
for (auto& mode : renderingModes)
{
for (auto& mode : renderingModes)
{
bm->Args({ cycle, isStructured, isMultiBlock, static_cast<int>(mode) });
}
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchSlice"), isStructured, isMultiBlock, mode);
auto search = bench_cycles.find(hash_val);
// If we can't find the hash, or we're not doing repetitions, reset to 0
if (search == bench_cycles.end())
bench_cycles[hash_val] = 0;
bm->Args({ isStructured, isMultiBlock, static_cast<int>(mode) });
}
}
}
@ -659,26 +731,35 @@ void BenchMeshRendering(::benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
const bool isStructured = static_cast<bool>(state.range(1));
const bool isMultiBlock = static_cast<bool>(state.range(2));
const bool isStructured = static_cast<bool>(state.range(0));
const bool isMultiBlock = static_cast<bool>(state.range(1));
vtkm::cont::Timer inputGenTimer{ device };
vtkm::cont::Timer renderTimer{ device };
vtkm::cont::Timer writeTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
vtkm::cont::Timer totalTimer{ device };
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchMeshRendering"), isStructured, isMultiBlock);
int* cycles = &(bench_cycles[hash_val]);
if (!benchmark_repetitions)
*cycles = 0;
for (auto _ : state)
{
(void)_;
totalTimer.Start();
// Disable the benchmark timers for the updating/creation of the datasets
state.PauseTiming(); // Stop timers.
inputGenTimer.Start();
BuildInputDataSet(*cycles, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
state.ResumeTiming(); // And resume timers.
std::vector<vtkm::cont::DataSet> dataSets =
isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet);
@ -687,11 +768,13 @@ void BenchMeshRendering(::benchmark::State& state)
renderTimer.Stop();
writeTimer.Start();
WriteToDisk(*canvas, RenderingMode::Mesh, "mesh", isStructured, isMultiBlock, cycle);
WriteToDisk(*canvas, RenderingMode::Mesh, "mesh", isStructured, isMultiBlock, *cycles);
writeTimer.Stop();
totalTimer.Stop();
(*cycles)++;
state.SetIterationTime(totalTimer.GetElapsedTime());
state.counters.insert(
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
@ -703,18 +786,21 @@ void BenchMeshRendering(::benchmark::State& state)
void BenchMeshRenderingGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock" });
bm->ArgNames({ "IsStructured", "IsMultiBlock" });
std::vector<uint32_t> isStructureds{ false, true };
std::vector<uint32_t> isMultiBlocks{ false, true };
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
for (auto& isStructured : isStructureds)
{
for (auto& isStructured : isStructureds)
for (auto& isMultiBlock : isMultiBlocks)
{
for (auto& isMultiBlock : isMultiBlocks)
{
bm->Args({ cycle, isStructured, isMultiBlock });
}
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchMeshRendering"), isStructured, isMultiBlock);
auto search = bench_cycles.find(hash_val);
// If we can't find the hash, or we're not doing repetitions, reset to 0
if (search == bench_cycles.end())
bench_cycles[hash_val] = 0;
bm->Args({ isStructured, isMultiBlock });
}
}
}
@ -725,24 +811,33 @@ void BenchVolumeRendering(::benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
const bool isStructured = true;
const bool isMultiBlock = static_cast<bool>(state.range(1));
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
const bool isMultiBlock = static_cast<bool>(state.range(0));
vtkm::cont::Timer totalTimer{ device };
vtkm::cont::Timer renderTimer{ device };
vtkm::cont::Timer writeTimer{ device };
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchVolumeRendering"), isMultiBlock);
int* cycles = &(bench_cycles[hash_val]);
if (!benchmark_repetitions)
*cycles = 0;
for (auto _ : state)
{
(void)_;
totalTimer.Start();
// Disable the benchmark timers for the updating/creation of the datasets
state.PauseTiming(); // Stop timers.
vtkm::cont::Timer inputGenTimer{ device };
inputGenTimer.Start();
BuildInputDataSet(*cycles, isStructured, isMultiBlock, DataSetDim);
inputGenTimer.Stop();
state.ResumeTiming(); // And resume timers.
renderTimer.Start();
std::vector<vtkm::cont::DataSet> dataSets =
isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet);
@ -750,11 +845,13 @@ void BenchVolumeRendering(::benchmark::State& state)
renderTimer.Stop();
writeTimer.Start();
WriteToDisk(*canvas, RenderingMode::Volume, "volume", isStructured, isMultiBlock, cycle);
WriteToDisk(*canvas, RenderingMode::Volume, "volume", isStructured, isMultiBlock, *cycles);
writeTimer.Stop();
totalTimer.Stop();
(*cycles)++;
state.SetIterationTime(totalTimer.GetElapsedTime());
state.counters.insert(
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
@ -766,15 +863,18 @@ void BenchVolumeRendering(::benchmark::State& state)
void BenchVolumeRenderingGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "Cycle", "IsMultiBlock" });
bm->ArgNames({ "IsMultiBlock" });
std::vector<uint32_t> isMultiBlocks{ false };
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
for (auto& isMultiBlock : isMultiBlocks)
{
for (auto& isMultiBlock : isMultiBlocks)
{
bm->Args({ cycle, isMultiBlock });
}
size_t hash_val = 0;
hash_combine(hash_val, std::string("BenchVolumeRendering"), isMultiBlock);
auto search = bench_cycles.find(hash_val);
// If we can't find the hash, or we're not doing repetitions, reset to 0
if (search == bench_cycles.end())
bench_cycles[hash_val] = 0;
bm->Args({ isMultiBlock });
}
}
@ -884,55 +984,6 @@ 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;
}
} // end anon namespace
@ -954,5 +1005,29 @@ int main(int argc, char* argv[])
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
}
bool benchmark_min_time = false;
bool benchmark_report_aggregates_only = false;
for (auto i = 0; i <= argc; i++)
if (!strncmp(args[i], "--benchmark_repetitions", 23))
benchmark_repetitions = true;
else if (!strncmp(args[i], "--benchmark_min_time", 20))
benchmark_min_time = true;
else if (!strncmp(args[i], "--benchmark_report_aggregates_only", 34))
benchmark_report_aggregates_only = true;
// If repetitions are explicitly set without also specifying a minimum_time,
// force the minimum time to be fairly small so that in all likelyhood, benchmarks
// will only run 1 iteration for each test
//
// And, for good measure, only output the accumulated statistics
if (benchmark_repetitions)
{
if (!benchmark_min_time)
args[argc++] = strdup("--benchmark_min_time=0.00000001");
if (!benchmark_report_aggregates_only)
args[argc++] = strdup("--benchmark_report_aggregates_only=true");
}
VTKM_EXECUTE_BENCHMARKS(argc, args.data());
}

@ -10,17 +10,14 @@
#include "Benchmarker.h"
#include <vtkm/Particle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/ErrorInternal.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/internal/OptionParser.h>
#include <vtkm/filter/ParticleAdvection.h>
#include <vtkm/worklet/particleadvection/EulerIntegrator.h>
#include <vtkm/worklet/particleadvection/RK4Integrator.h>
#include <vtkm/filter/flow/ParticleAdvection.h>
namespace
{
@ -50,7 +47,7 @@ void BenchParticleAdvection(::benchmark::State& state)
vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1),
vtkm::Particle(vtkm::Vec3f(.2f, 3.0f, .2f), 2) });
vtkm::filter::ParticleAdvection particleAdvection;
vtkm::filter::flow::ParticleAdvection particleAdvection;
particleAdvection.SetStepSize(vtkm::FloatDefault(1) / state.range(0));
particleAdvection.SetNumberOfSteps(static_cast<vtkm::Id>(state.range(0)));

@ -48,14 +48,6 @@ set(benchmarks
BenchmarkTopologyAlgorithms
)
#Taking too long to compile with HIPCC
if(HIP IN_LIST Kokkos_DEVICES)
list(REMOVE_ITEM benchmarks
BenchmarkDeviceAdapter
BenchmarkODEIntegrators
)
endif()
set(VTKm_BENCHS_RANGE_LOWER_BOUNDARY 4096 CACHE STRING "Smallest sample for input size bench for BenchmarkDeviceAdapter")
set(VTKm_BENCHS_RANGE_UPPER_BOUNDARY 134217728 CACHE STRING "Biggest sample for input size bench for BenchmarkDeviceAdapter")
mark_as_advanced(VTKm_BENCHS_RANGE_LOWER_BOUNDARY VTKm_BENCHS_RANGE_UPPER_BOUNDARY)
@ -64,10 +56,8 @@ foreach (benchmark ${benchmarks})
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter vtkm_io)
endforeach ()
if(NOT HIP IN_LIST Kokkos_DEVICES)
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_LOWER_BOUNDARY=${VTKm_BENCHS_RANGE_LOWER_BOUNDARY})
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_UPPER_BOUNDARY=${VTKm_BENCHS_RANGE_UPPER_BOUNDARY})
endif()
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_LOWER_BOUNDARY=${VTKm_BENCHS_RANGE_LOWER_BOUNDARY})
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_UPPER_BOUNDARY=${VTKm_BENCHS_RANGE_UPPER_BOUNDARY})
if(TARGET vtkm_rendering)
add_benchmark(NAME BenchmarkRayTracing FILE BenchmarkRayTracing.cxx LIBS vtkm_rendering vtkm_source)

@ -0,0 +1,20 @@
This document describes how to use the command-line options for Google Benchmarks (GBench) to control the behavior of BenchmarkInSitu.
Generally, "BenchmarkInSitu --help" will provide the list of standard benchmarks along with the associated ones from GBench.
As a refresher, GBench iterates a test defined in the application, in this case, Contour, Streamlines, ..., a number of times until two criteria are met, a statistically stable set of samples have been generated, and the test ran for a specified minimum amount of time (by default, 0.5 seconds).
There are three ways to run the InSitu benchmark that control the number of iterations run by GBench. These are independent of the "standard" arguments passed to the benchmark (we'll define the standard arguments as: --vtkm-device, --size, --image-size, plus other not defined by GBench).
1. BenchmarkInSitu <standard arguments>
- Under this scenario, the iterations are controlled completely by GBench. Generally, each test will be run between 1 and N iterations depending on how long each test runs.
2. BenchmarkInSitu <standard arguments> --benchmark_min_time=<min_time>
- This will ensure that the test will run for at least <min_time> seconds. You will set this option if you don't care about the actual number of iterations, but only that each test runs for at least a specified time.
3. BenchmarkInSitu <standard arguments> --benchmark_repetitions=<reps>
- The purpose of this option is to *exactly* control the number of iterations performed by GBench. Internally, this does two things:
- Sets the minimum time to a very small value ("--benchmark_min_time=0.00000001")
- Sets the output to only report aggregate statistics for each test, e.g., mean, median, standard deviation (--benchmark_report_aggregates_only=true)
Both of these arguments can be overridden by providing different values on the command-line. With the current setting, all test runs have resulted in only <reps> repetitions being executed.

@ -27,6 +27,5 @@ Libs: -L${libdir} \
-lvtkm_worklet-@VTKm_VERSION@ \
-lvtkm_source-@VTKm_VERSION@ \
-lvtkm_io-@VTKm_VERSION@ \
-lvtkm_lodepng-@VTKm_VERSION@ \
-lvtkm_cont-@VTKm_VERSION@ \
-lvtkmdiympi_nompi

@ -34,6 +34,5 @@ VTKm_LIB_FLAGS = -L $(VTKm_DIR)/lib \
-lvtkm_worklet-$(VTKM_VERSION) \
-lvtkm_source-$(VTKM_VERSION) \
-lvtkm_io-$(VTKM_VERSION) \
-lvtkm_lodepng-$(VTKM_VERSION) \
-lvtkm_cont-$(VTKM_VERSION) \
-lvtkmdiympi_nompi

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

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

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

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

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

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

78
docs/HotFixGuide.md Normal file

@ -0,0 +1,78 @@
# HotFix Guide
## HotFix general instructions
The following instructions intend to be general case for applying hotfixes in
release branches, for more specific cases, simplified instructions are to be
found in the below sub-sections.
1. Find the oldest relevant release branch BASE to which this hotfix applies.
- Relevant release branches include: release, and release-specific
maintained branches.
2. Create a hotfix branch branching from BASE.
- if the hotfix branch already exists `git rebase --onto BASE`.
3. Open a merge-request targeting:
- master, if applies to master.
- Otherwise, release, if applies to the latest release.
- Otherwise, the most recent release-specific branch to which this hotfix
applies.
- Lastly, if none of above, BASE.
4. (If needed) If the hotfix is a backport (cherry-picked) of an existing merge-requests,
add a cross-reference each of the existing merge-request with the format of `!1234`
inside the description of the newly created merge-request.
- Cherry-pick each of the relevant commits of the existing merge-requests using
`git cherry-pick -x XXYYZZ`.
5. At the bottom of the description of the merge-request add: `Backport: branch_name`
directive for each of the branches that exists between BASE (inclusive) and
the branch that we target our merge-request (exclusive).
In the case of merge conflicts in any of the backports refer to [Kitware backport guide][1].
## HotFix for latest release and master branch only
For hotfixes that applies to release and master branch, create a branch based
off of the tip of the release branch and create a merge-request targeting master.
If the hotfix branch already exists based off of a commit in the master branch,
you can change the base branch of the hotfix branch from master to latest
release with:
```
# Assuming that both your local master and release branch are updated; and
# assuming that you are currently in your topic branch
git rebase --onto release master
```
Next, you can bring this commit to __release__ by adding the following line to
the bottom of the MR description: `Backport: release`. This directive will later
internally instruct the Kitware Robot to bring the changes of the hotfix branch
creating a merge commit in the release branch with its second parent being the
hotfix branch tip.
Lastly, the master branch history will be automatically connected with
release after the merge-request is merged as explained in
[here](#How-master-and-release-branch-are-connected).
## HotFix for release branch only
For hotfixes that only applies to release branch, whose changes are unneeded in
master, create a branch based off of the __release__ branch and create a
merge-request targeting __release__ branch. Proceed as in a regular MR.
### How master and release branch are connected
Every merge commit in the release branch will be automatically connected to
master branch by our Gitlab robot creating a merge-request using the
`-s ours` strategy, __note__ that `-s ours` strategy does not actually bring any
change to the target branch, it will solely create an empty merge commit in master
connecting release branch..
## Other cases
There are more possible case scenarios that you might encounter while attempting
to bring a hotfix to release, for further cases please refer to the
[Kitware backport guide][1] which this document is based of.
[1]: https://gitlab.kitware.com/utils/git-workflow/-/wikis/Backport-topics

@ -1,55 +0,0 @@
Release HotFix
===============
# HotFix from master branch
## On a single MR
You have created a branch from master branch and you have a MR request targeting
the __master__ branch.
You can bring this commit to __release__ by adding the following line to
the bottom of the MR description.
```
Backport: release
```
This will cherry-pick this commit and push it to __release__ after typing `Do:
merge` in a comment.
You must also make sure that there will not be any merge conflict with the
__release__ branch, thus you need to create an additional commit using the following
command:
```
git merge --no-ff origin/release
```
This will ensure that backport will be able to push your commit to __release__.
## On multiple MRs
1. Create one merge request sourcing your HotFix branch and targeting __master__
and merge.
2. Create one merge request sourcing __master__ and targeting __release__ and merge.
# HotFix from release branch
You have created a branch from the __release__ branch and you have a MR request
targeting __release__, you can proceed as in a regular MR.
Every merge in release will be automatically brought to master by the robot
using `-s ours` strategy.
__VERY IMPORTANT__: `-s ours` strategy does not actually bring any change to the
target branch, thus if needed you might want to bring the changes
from the HotFix to __master__ by creating a another MR which cherry-picks
the merge commit in `release` for the given HotFix.
Use the difference to first parent for the cherry-pick commit:
```
git cherry-pick -m1 -x <HASH OF COMMIT>
```

@ -3,7 +3,7 @@ Release Process
## Prologue
This document is divided in two parts:
This document is divided in two parts:
- A overview of the branching and release scheme used in VTK-m.
- A concise instructions to get started with the release process.
@ -18,10 +18,30 @@ While all of the development is performed in the master branch, once in a while
when we want to do a release, we tag a commit in master and we push it to the
release branch.
Also there are times when we want to get _Hotfix_ that affects previous releases
Also there are times when we want to get _hotfix_ that affects previous releases
to the release branch, in this case we can also push the merge request commit
with the fix into the release branch.
## Release-specific branches
Sometime we need to keep maintaining an older release which does not sit at the
tip of the release branch. For this purpose we use release-specific branches
with the name of `release-@MAJOR_VER@.@MINOR_VER@`.
To create a new release-specific branch you need someone with push access to
create a release-specific branch pointing at the latest commit of the minor
release of interest, this is, for release-1.7 it will be v1.7.1 as opposed to
v1.7.0.
There can be the case that between release X.Y and X.Y+1 there are hotfixes
commits that do not correspond to a patch tag releases. In this particular case,
create the release-specific branch pointing to the last commit before X.Y+1.
To add a hotfix to a release-specific branch, follow the instructions described
in [HotFixes](./ReleaseHotFix.md) noting that you need to adjust the branch
names from release to `release-@MAJOR_VER@.@MINOR_VER@`.
A not so simple example of how the branching scheme looks like can be found
here:
@ -29,28 +49,28 @@ here:
# → git log --graph --decorate --oneline --all
* 2e9230d (master) Merge branch 'update'
|\
|\
| * 59279dd (HEAD -> release, tag: v1.0.1) v1.0.1 2nd release of VTKm
| * b60611b Add release notes for v1.0.1
| * 9d26451 Merge branch 'master' into update
| |\
| |/
|/|
| |\
| |/
|/|
* | 75137e5 Unrelated commit
* | e982be0 Merge branch 'release'
|\|
|\|
| * f2c4eb6 Merge branch 'hotfix' into release
| |\
| |\
| | * c1c2655 Hotfix
| |/
| |/
* | e53df9e Unrelated commit
* | ec6b481 Unrelated commit
|/
|/
* 0742a47 (tag: v1.0.0) v1.0.0 1st release of VTKm
* 4fe993c Add release notes for v1.0.0
```
This will make the release branch to only contain tags and _HotFix_ merges as
This will make the release branch to only contain tags and _hotfix_ merges as
shown in here:
```git

23
docs/ReleaseRoadmap.md Normal file

@ -0,0 +1,23 @@
# Minor 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 | | Short Term* | TBD |
| 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 |
## Legend
- Version: Only counts major and minor versions, patch releases are released
unscheduled as needed.
- Date: Scheduled date for the Final Release of the corresponding release.
- Delay: Days of delay between scheduled date and release date.
- Life-cycle: The duration of the support:
- Long Term, usually maintained for one natural year, it might use a
specific-release support branch if it is not the latest release.
- Short Term, usually maintained until the next minor release, usually 3-6
months.

@ -0,0 +1,5 @@
# Fix bug with copying invalid variants
There was a bug where if you attempted to copy a `Variant` that was not
valid (i.e. did not hold an object); a seg fault could happen. This has
been changed to set the target variant to also be invalid.

@ -0,0 +1,14 @@
# Add test for array and datas that are cleaned up after finalize
It is the case that arrays might be deallocated from a device after the
device is closed. This can happen, for example, when an `ArrayHandle` is
declared globally. It gets constructed before VTK-m is initialized. This
is OK as long as you do not otherwise use it until VTK-m is initialized.
However, if you use that `ArrayHandle` to move data to a device and that
data is left on the device when the object closes, then the
`ArrayHandle` will be left holding a reference to invalid device memory
once the device is shut down. This can cause problems when the
`ArrayHandle` destructs itself and attempts to release this memory.
The VTK-m devices should gracefully handle deallocations that happen
after device shutdown.

@ -0,0 +1,9 @@
# Old Filter Base Classes are Deprecated
In recent versions of VTK-m, a new structure for filter classes was
introduced. All of the existing filters have been moved over to this new
structure, and the old filter class structure has been deprecated.
This is in preparation for changed in VTK-m 2.0, where the old filter
classes will be removed and the new filter classes will have the `New` in
their name removed (so that they become simply `Filter` and `FilterField`).

@ -0,0 +1,15 @@
# Fix type comparison on OSX
`UnknownArrayHandle` compares `std::type_index` objects to check whether a
requested type is the same as that held in the array handle. However, it is
possible that different translation units can create different but
equivalent `std::type_info`/`std::type_index` objects. In this case, the
`==` operator might return false for two equivalent types. This can happen
on OSX.
To get around this problem, `UnknownArrayHandle` now does a more extensive
check for `std::type_info` object. It first uses the `==` operator to
compare them (as before), which usually works but can possibly return
`false` when the correct result is `true`. To check for this case, it then
compares the name for the two types and returns `true` iff the two names
are the same.

@ -0,0 +1,30 @@
# Allow ArrayHandle to have a runtime selectable number of buffers
Previously, the number of buffers held by an `ArrayHandle` had to be
determined statically at compile time by the storage. Most of the time this
is fine. However, there are some exceptions where the number of buffers
need to be selected at runtime. For example, the `ArrayHandleRecombineVec`
does not specify the number of components it uses, and it needed a hack
where it stored buffers in the metadata of another buffer, which is bad.
This change allows the number of buffers to vary at runtime (at least at
construction). The buffers were already managed in a `std::vector`. It now
no longer forces the vector to be a specific size. `GetNumberOfBuffers` was
removed from the `Storage`. Instead, if the number of buffers was not
specified at construction, an allocation of size 0 is done to create
default buffers.
The biggest change is to the interface of the storage object methods, which
now take `std::vector` instead of pointers to `Buffer` objects. This adds a
little hassle in having to copy subsets of this `vector` when a storage
object has multiple sub-arrays. But it does simplify some of the
templating.
Other changes to the `Storage` structure include requiring all objects to
include a `CreateBuffers` method that accepts no arguments. This method
will be used by `ArrayHandle` in its default constructor. Previously,
`ArrayHandle` would create the `vector` of `Buffer` objects itself, but it
now must call this method in the `Storage` to do this. (It also has a nice
side effect of allowing the `Storage` to initialize the buffer objects if
necessary. Another change was to remove the `GetNumberOfBuffers` method
(which no longer has meaning).

@ -0,0 +1,17 @@
# Divided the mesh quality filter
The original implementation of the `MeshQuality` filter created one large
kernel with a switch statement that jumped to the code of the metric
actually desired. This is problematic for a couple of reasons. First, it
takes the compiler a long time to optimize for all the inlined cases of a
large kernel. Second, it creates a larger than necessary function that has
to be loaded onto the GPU to execute.
The code was modified to move the switch statement outside of the GPU
kernel. Instead, the routine for each metric is compiled into its own
kernel. For convenience, each routine is wrapped into its own independent
filter (e.g., `MeshQualityArea`, `MeshQualityVolume`). The uber
`MeshQuality` filter still exists, and its use is still encouraged even if
you only need a particular metric. However, internally the switch statement
now occurs on the host to select the appropriate specific filter that loads
a more targeted kernel.

@ -0,0 +1,10 @@
# Added DEVICE_SOURCES to vtkm_unit_tests
The `vtkm_unit_tests` function in the CMake build now allows you to specify
which files need to be compiled with a device compiler using the
`DEVICE_SOURCES` argument. Previously, the only way to specify that unit
tests needed to be compiled with a device compiler was to use the
`ALL_BACKENDS` argument, which would automatically compile everything with
the device compiler as well as test the code on all backends.
`ALL_BACKENDS` is still supported, but it no longer changes the sources to
be compiled with the device compiler.

@ -0,0 +1,11 @@
# Do not require `VecTraits` for `UnknownArrayHandle` components
Whan an `UnknownArrayHandler` is constructed from an `ArrayHandle`, it uses
the `VecTraits` of the component type to construct its internal functions.
This meant that you could not put an `ArrayHandle` with a component type
that did not have `VecTraits` into an `UnknownArrayHandle`.
`UnknownArrayHandle` now no longer needs the components of its arrays to
have `VecTraits`. If the component type of the array does not have
`VecTraits`, it treats the components as if they are a scalar type.

@ -0,0 +1,5 @@
# Add Variant::IsType
The `Variant` class was missing a way to check the type. You could do it
indirectly using `variant.GetIndex() == variant.GetIndexOf<T>()`, but
having this convenience function is more clear.

@ -0,0 +1,7 @@
# Fix bug with voxels in legacy vtk files
The legacy VTK file reader for unstructured grids had a bug when reading
cells of type voxel. VTK-m does not support the voxel cell type in
unstructured grids (i.e. explicit cell sets), so it has to convert them to
hexahedron cells. A bug in the reader was mangling the cell array index
during this conversion.

@ -15,7 +15,3 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Clipping Clipping.cxx)
target_link_libraries(Clipping PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Clipping
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Clipping.cxx)

@ -18,9 +18,3 @@ target_link_libraries(ContourTreeMesh2D vtkm_filter)
add_executable(ContourTreeMesh3D ContourTreeMesh3D.cxx)
target_link_libraries(ContourTreeMesh3D vtkm_filter)
vtkm_add_target_information(ContourTreeMesh2D ContourTreeMesh3D
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
ContourTreeMesh2D.cxx ContourTreeMesh3D.cxx)

@ -58,7 +58,7 @@
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/ContourTreeUniform.h>
#include <vtkm/filter/scalar_topology/ContourTreeUniform.h>
#include <fstream>
#include <vector>
@ -105,7 +105,7 @@ int main(int argc, char* argv[])
inDataSet.AddPointField("values", values);
// Convert 2D mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeMesh2D filter;
vtkm::filter::scalar_topology::ContourTreeMesh2D filter;
filter.SetActiveField("values");
// Output data set is pairs of saddle and peak vertex IDs
vtkm::cont::DataSet output = filter.Execute(inDataSet);

@ -58,7 +58,7 @@
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/ContourTreeUniform.h>
#include <vtkm/filter/scalar_topology/ContourTreeUniform.h>
#include <fstream>
#include <vector>
@ -106,7 +106,7 @@ int main(int argc, char* argv[])
inDataSet.AddPointField("values", values);
// Convert 3D mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeMesh3D filter;
vtkm::filter::scalar_topology::ContourTreeMesh3D filter;
filter.SetActiveField("values");
// Output data set is pairs of saddle and peak vertex IDs
vtkm::cont::DataSet output = filter.Execute(inDataSet);

@ -71,11 +71,12 @@
#include <vtkm/cont/Timer.h>
#include <vtkm/io/BOVDataSetReader.h>
#include <vtkm/filter/ContourTreeUniformAugmented.h>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/processcontourtree/Branch.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/filter/scalar_topology/ContourTreeUniformAugmented.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/processcontourtree/Branch.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
@ -153,6 +154,122 @@ private:
std::vector<std::string> mCLOptions;
};
inline vtkm::Id3 ComputeNumberOfBlocksPerAxis(vtkm::Id3 globalSize, vtkm::Id numberOfBlocks)
{
vtkm::Id currNumberOfBlocks = numberOfBlocks;
vtkm::Id3 blocksPerAxis{ 1, 1, 1 };
while (currNumberOfBlocks > 1)
{
vtkm::IdComponent splitAxis = 0;
for (vtkm::IdComponent d = 1; d < 3; ++d)
{
if (globalSize[d] > globalSize[splitAxis])
{
splitAxis = d;
}
}
if (currNumberOfBlocks % 2 == 0)
{
blocksPerAxis[splitAxis] *= 2;
globalSize[splitAxis] /= 2;
currNumberOfBlocks /= 2;
}
else
{
blocksPerAxis[splitAxis] *= currNumberOfBlocks;
break;
}
}
return blocksPerAxis;
}
inline std::tuple<vtkm::Id3, vtkm::Id3, vtkm::Id3> ComputeBlockExtents(vtkm::Id3 globalSize,
vtkm::Id3 blocksPerAxis,
vtkm::Id blockNo)
{
// DEBUG: std::cout << "ComputeBlockExtents("<<globalSize <<", " << blocksPerAxis << ", " << blockNo << ")" << std::endl;
// DEBUG: std::cout << "Block " << blockNo;
vtkm::Id3 blockIndex, blockOrigin, blockSize;
for (vtkm::IdComponent d = 0; d < 3; ++d)
{
blockIndex[d] = blockNo % blocksPerAxis[d];
blockNo /= blocksPerAxis[d];
float dx = float(globalSize[d] - 1) / float(blocksPerAxis[d]);
blockOrigin[d] = vtkm::Id(blockIndex[d] * dx);
vtkm::Id maxIdx =
blockIndex[d] < blocksPerAxis[d] - 1 ? vtkm::Id((blockIndex[d] + 1) * dx) : globalSize[d] - 1;
blockSize[d] = maxIdx - blockOrigin[d] + 1;
// DEBUG: std::cout << " " << blockIndex[d] << dx << " " << blockOrigin[d] << " " << maxIdx << " " << blockSize[d] << "; ";
}
// DEBUG: std::cout << " -> " << blockIndex << " " << blockOrigin << " " << blockSize << std::endl;
return std::make_tuple(blockIndex, blockOrigin, blockSize);
}
inline vtkm::cont::DataSet CreateSubDataSet(const vtkm::cont::DataSet& ds,
vtkm::Id3 blockOrigin,
vtkm::Id3 blockSize,
const std::string& fieldName)
{
vtkm::Id3 globalSize;
ds.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetPointDimensions(), globalSize);
const vtkm::Id nOutValues = blockSize[0] * blockSize[1] * blockSize[2];
const auto inDataArrayHandle = ds.GetPointField(fieldName).GetData();
vtkm::cont::ArrayHandle<vtkm::Id> copyIdsArray;
copyIdsArray.Allocate(nOutValues);
auto copyIdsPortal = copyIdsArray.WritePortal();
vtkm::Id3 outArrIdx;
for (outArrIdx[2] = 0; outArrIdx[2] < blockSize[2]; ++outArrIdx[2])
for (outArrIdx[1] = 0; outArrIdx[1] < blockSize[1]; ++outArrIdx[1])
for (outArrIdx[0] = 0; outArrIdx[0] < blockSize[0]; ++outArrIdx[0])
{
vtkm::Id3 inArrIdx = outArrIdx + blockOrigin;
vtkm::Id inIdx = (inArrIdx[2] * globalSize[1] + inArrIdx[1]) * globalSize[0] + inArrIdx[0];
vtkm::Id outIdx =
(outArrIdx[2] * blockSize[1] + outArrIdx[1]) * blockSize[0] + outArrIdx[0];
VTKM_ASSERT(inIdx >= 0 && inIdx < inDataArrayHandle.GetNumberOfValues());
VTKM_ASSERT(outIdx >= 0 && outIdx < nOutValues);
copyIdsPortal.Set(outIdx, inIdx);
}
// DEBUG: std::cout << copyIdsPortal.GetNumberOfValues() << std::endl;
vtkm::cont::Field permutedField;
bool success =
vtkm::filter::MapFieldPermutation(ds.GetPointField(fieldName), copyIdsArray, permutedField);
if (!success)
throw vtkm::cont::ErrorBadType("Field copy failed (probably due to invalid type)");
vtkm::cont::DataSetBuilderUniform dsb;
if (globalSize[2] <= 1) // 2D Data Set
{
vtkm::Id2 dimensions{ blockSize[0], blockSize[1] };
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::CellSetStructured<2> cellSet;
cellSet.SetPointDimensions(dimensions);
cellSet.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cellSet.SetGlobalPointIndexStart(vtkm::Id2{ blockOrigin[0], blockOrigin[1] });
dataSet.SetCellSet(cellSet);
dataSet.AddField(permutedField);
return dataSet;
}
else
{
vtkm::cont::DataSet dataSet = dsb.Create(blockSize);
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(blockSize);
cellSet.SetGlobalPointDimensions(globalSize);
cellSet.SetGlobalPointIndexStart(blockOrigin);
dataSet.SetCellSet(cellSet);
dataSet.AddField(permutedField);
return dataSet;
}
}
// Compute and render an isosurface for a uniform grid example
@ -171,7 +288,6 @@ int main(int argc, char* argv[])
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &size);
int numBlocks = size;
int blocksPerRank = 1;
#endif
// initialize vtkm-m (e.g., logging via -v and device via the -d option)
@ -354,7 +470,7 @@ int main(int argc, char* argv[])
// From https://www.unix.com/302983597-post2.html
char cstr_filename[32];
snprintf(cstr_filename, sizeof(cstr_filename), "cout_%d.log", rank);
int out = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
int out = open(cstr_filename, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0600);
if (-1 == out)
{
perror("opening cout.log");
@ -362,7 +478,7 @@ int main(int argc, char* argv[])
}
snprintf(cstr_filename, sizeof(cstr_filename), "cerr_%d.log", rank);
int err = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
int err = open(cstr_filename, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0600);
if (-1 == err)
{
perror("opening cerr.log");
@ -396,43 +512,15 @@ int main(int argc, char* argv[])
std::vector<vtkm::Id> dims;
if (filename.compare(filename.length() - 3, 3, "bov") == 0)
{
std::cout << "Reading BOV file" << std::endl;
vtkm::io::BOVDataSetReader reader(filename);
inDataSet = reader.ReadDataSet();
nDims = 3;
currTime = totalTime.GetElapsedTime();
dataReadTime = currTime - prevTime;
prevTime = currTime;
#ifdef WITH_MPI
// Copy the data into the values array so we can construct a multiblock dataset
// TODO All we should need to do to implement BOV support is to copy the values
// in the values vector and copy the dimensions in the dims vector
vtkm::Id3 meshSize;
vtkm::worklet::contourtree_augmented::GetPointDimensions temp;
temp(inDataSet.GetCellSet(), meshSize);
dims[0] = meshSize[0];
dims[1] = meshSize[1];
dims[2] = meshSize[2];
// TODO/FIXME: The following is commented out since it creates a a warning that
// AsVirtual() will no longer be supported. Since this implementation is
// incomplete anyway, it currently makes more sense to comment it out than
// to fix the warning.
// auto tempField = inDataSet.GetField("values").GetData();
// values.resize(static_cast<std::size_t>(tempField.GetNumberOfValues()));
// auto tempFieldHandle = tempField.AsVirtual<ValueType>().ReadPortal();
// for (vtkm::Id i = 0; i < tempField.GetNumberOfValues(); i++)
// {
// values[static_cast<std::size_t>(i)] = static_cast<ValueType>(tempFieldHandle.Get(i));
// }
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"BOV reader not yet support in MPI mode by this example");
MPI_Finalize();
return EXIT_FAILURE;
#endif
}
else // Read ASCII data input
{
std::cout << "Reading ASCII file" << std::endl;
std::ifstream inFile(filename);
if (inFile.bad())
return 0;
@ -485,7 +573,6 @@ int main(int argc, char* argv[])
// swap dims order
std::swap(dims[0], dims[1]);
#ifndef WITH_MPI // We only need the inDataSet if are not using MPI otherwise we'll constructe a multi-block dataset
// build the input dataset
vtkm::cont::DataSetBuilderUniform dsb;
// 2D data
@ -506,7 +593,6 @@ int main(int argc, char* argv[])
inDataSet = dsb.Create(vdims);
}
inDataSet.AddPointField("values", values);
#endif
} // END ASCII Read
// Print the mesh metadata
@ -538,104 +624,49 @@ int main(int argc, char* argv[])
#ifndef WITH_MPI // construct regular, single-block VTK-M input dataset
vtkm::cont::DataSet useDataSet = inDataSet; // Single block dataset
#else // Create a multi-block dataset for multi-block DIY-paralle processing
vtkm::cont::PartitionedDataSet useDataSet; // Partitioned variant of the input dataset
vtkm::Id3 blocksPerDim =
nDims == 3 ? vtkm::Id3(1, 1, numBlocks) : vtkm::Id3(1, numBlocks, 1); // Decompose the data into
// Determine split
vtkm::Id3 globalSize = nDims == 3 ? vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(dims[2]))
: vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(0));
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
localBlockIndices.Allocate(blocksPerRank);
localBlockOrigins.Allocate(blocksPerRank);
localBlockSizes.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
static_cast<vtkm::Id>(1));
vtkm::Id3 blocksPerDim = ComputeNumberOfBlocksPerAxis(globalSize, numBlocks);
vtkm::Id blocksPerRank = numBlocks / size;
vtkm::Id numRanksWithExtraBlock = numBlocks % size;
vtkm::Id blocksOnThisRank, startBlockNo;
if (rank < numRanksWithExtraBlock)
{
vtkm::Id lastDimSize =
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
if (size > (lastDimSize / 2.))
{
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
rank == 0,
"Number of ranks too large for data. Use " << lastDimSize / 2
<< "or fewer ranks");
MPI_Finalize();
return EXIT_FAILURE;
}
vtkm::Id standardBlockSize = (vtkm::Id)(lastDimSize / numBlocks);
vtkm::Id blockSize = standardBlockSize;
vtkm::Id blockSliceSize =
nDims == 2 ? static_cast<vtkm::Id>(dims[0]) : static_cast<vtkm::Id>((dims[0] * dims[1]));
vtkm::Id blockNumValues = blockSize * blockSliceSize;
blocksOnThisRank = blocksPerRank + 1;
startBlockNo = (blocksPerRank + 1) * rank;
}
else
{
blocksOnThisRank = blocksPerRank;
startBlockNo = numRanksWithExtraBlock * (blocksPerRank + 1) +
(rank - numRanksWithExtraBlock) * blocksPerRank;
}
vtkm::Id startBlock = blocksPerRank * rank;
vtkm::Id endBlock = startBlock + blocksPerRank;
for (vtkm::Id blockIndex = startBlock; blockIndex < endBlock; ++blockIndex)
{
vtkm::Id localBlockIndex = blockIndex - startBlock;
vtkm::Id blockStart = blockIndex * blockNumValues;
vtkm::Id blockEnd = blockStart + blockNumValues;
if (blockIndex < (numBlocks - 1)) // add overlap between regions
{
blockEnd += blockSliceSize;
}
else
{
blockEnd = lastDimSize * blockSliceSize;
}
vtkm::Id currBlockSize = (vtkm::Id)((blockEnd - blockStart) / blockSliceSize);
if (blocksOnThisRank != 1)
{
std::cerr << "Currently only one block per rank supported!";
MPI_Finalize();
return EXIT_FAILURE;
}
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::cont::DataSet ds;
// Created partitioned (split) data set
vtkm::cont::PartitionedDataSet useDataSet;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
localBlockIndices.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
// 2D data
if (nDims == 2)
{
vtkm::Id2 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[0]);
vdims[1] = static_cast<vtkm::Id>(currBlockSize);
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
vtkm::Vec<ValueType, 2> spacing(1, 1);
ds = dsb.Create(vdims, origin, spacing);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(blockIndex, 0, 0));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3((blockStart / blockSliceSize), 0, 0));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(currBlockSize, static_cast<vtkm::Id>(dims[0]), 0));
}
// 3D data
else
{
vtkm::Id3 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[1]);
vdims[1] = static_cast<vtkm::Id>(dims[0]);
vdims[2] = static_cast<vtkm::Id>(currBlockSize);
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
ds = dsb.Create(vdims, origin, spacing);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
localBlockSizesPortal.Set(
localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), static_cast<vtkm::Id>(dims[1]), currBlockSize));
}
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
(values.begin() + blockEnd));
ds.AddPointField("values", subValues);
useDataSet.AppendPartition(ds);
}
for (vtkm::Id blockNo = 0; blockNo < blocksOnThisRank; ++blockNo)
{
vtkm::Id3 blockOrigin, blockSize, blockIndex;
std::tie(blockIndex, blockOrigin, blockSize) =
ComputeBlockExtents(globalSize, blocksPerDim, startBlockNo + blockNo);
useDataSet.AppendPartition(CreateSubDataSet(inDataSet, blockOrigin, blockSize, "values"));
localBlockIndicesPortal.Set(blockNo, blockIndex);
}
#endif // WITH_MPI construct input dataset
@ -644,11 +675,11 @@ int main(int argc, char* argv[])
prevTime = currTime;
// Convert the mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeAugmented filter(useMarchingCubes, computeRegularStructure);
vtkm::filter::scalar_topology::ContourTreeAugmented filter(useMarchingCubes,
computeRegularStructure);
#ifdef WITH_MPI
filter.SetSpatialDecomposition(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
filter.SetBlockIndices(blocksPerDim, localBlockIndices);
#endif
filter.SetActiveField("values");

@ -0,0 +1,77 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// COMMENTS:
//
// Input is assumed to be a sequence of lines of the form:
// I Global ID of branch root
// II Value of supernode
// III Global ID of supernode
//
// All lines are assumed to have been sorted already. Because of how the
// Unix sort utility operates (textual sort), the most we can assume is that all
// supernodes corresponding to a given branch root are sorted together.
//
// We therefore do simple stream processing, identifying new branches by
// the changes in root ID.
//
//=======================================================================================
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/BranchCompiler.h>
int main()
{ // main()
vtkm::worklet::contourtree_distributed::BranchCompiler compiler;
compiler.Parse(std::cin);
compiler.Print(std::cout);
return 0;
} // main()

@ -81,10 +81,16 @@ if (VTKm_ENABLE_MPI)
target_link_libraries(TreeCompiler vtkm_filter)
vtkm_add_target_information(TreeCompiler DROP_UNUSED_SYMBOLS)
add_executable(BranchCompiler BranchCompilerApp.cxx)
target_link_libraries(BranchCompiler vtkm_filter)
vtkm_add_target_information(BranchCompiler DROP_UNUSED_SYMBOLS)
configure_file(split_data_2d.py split_data_2d.py COPYONLY)
configure_file(split_data_3d.py split_data_3d.py COPYONLY)
configure_file(hact_test.sh hact_test.sh COPYONLY)
configure_file(hact_test_volume.sh hact_test_volume.sh COPYONLY)
configure_file(hact_test_branch_decomposition.sh hact_test_branch_decomposition.sh COPYONLY)
configure_file(testrun_branch_decomposition.sh testrun_branch_decomposition.sh COPYONLY)
configure_file(testrun.sh testrun.sh COPYONLY)
configure_file(testrun_volume.sh testrun_volume.sh COPYONLY)
endif()

@ -71,12 +71,14 @@
#include <vtkm/cont/Timer.h>
#include <vtkm/io/BOVDataSetReader.h>
#include <vtkm/filter/ContourTreeUniformDistributed.h>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
#include <vtkm/worklet/contourtree_distributed/TreeCompiler.h>
#include <vtkm/filter/scalar_topology/ContourTreeUniformDistributed.h>
#include <vtkm/filter/scalar_topology/DistributedBranchDecompositionFilter.h>
#include <vtkm/filter/scalar_topology/worklet/branch_decomposition/HierarchicalVolumetricBranchDecomposer.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ProcessContourTree.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/HierarchicalContourTree.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/TreeCompiler.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
@ -203,6 +205,19 @@ int main(int argc, char* argv[])
augmentHierarchicalTree = true;
}
bool computeHierarchicalVolumetricBranchDecomposition = false;
if (parser.hasOption("--computeVolumeBranchDecomposition"))
{
computeHierarchicalVolumetricBranchDecomposition = true;
if (!augmentHierarchicalTree)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Warning: --computeVolumeBranchDecomposition only "
"allowed augmentation. Enabling --augmentHierarchicalTree option.");
augmentHierarchicalTree = true;
}
}
bool useBoundaryExtremaOnly = true;
if (parser.hasOption("--useFullBoundary"))
{
@ -261,7 +276,7 @@ int main(int argc, char* argv[])
{
if (rank == 0)
{
std::cout << "ContourTreeAugmented <options> <fileName>" << std::endl;
std::cout << "ContourTreeDistributed <options> <fileName>" << std::endl;
std::cout << std::endl;
std::cout << "<fileName> Name of the input data file." << std::endl;
std::cout << "The file is expected to be ASCII with either: " << std::endl;
@ -284,6 +299,9 @@ int main(int argc, char* argv[])
<< std::endl;
std::cout << " and when using only boundary extrema." << std::endl;
std::cout << "--augmentHierarchicalTree Augment the hierarchical tree." << std::endl;
std::cout << "--computeVolumeBranchDecomposition Compute the volume branch decomposition. "
<< std::endl;
std::cout << " Requries --augmentHierarchicalTree to be set." << std::endl;
std::cout << "--preSplitFiles Input data is already pre-split into blocks." << std::endl;
std::cout << "--saveDot Save DOT files of the distributed contour tree " << std::endl
<< " computation (Default=False). " << std::endl;
@ -311,6 +329,9 @@ int main(int argc, char* argv[])
<< " mc=" << useMarchingCubes << std::endl
<< " useFullBoundary=" << !useBoundaryExtremaOnly << std::endl
<< " saveDot=" << saveDotFiles << std::endl
<< " augmentHierarchicalTree=" << augmentHierarchicalTree << std::endl
<< " computeVolumetricBranchDecomposition="
<< computeHierarchicalVolumetricBranchDecomposition << std::endl
<< " saveOutputData=" << saveOutputData << std::endl
<< " forwardSummary=" << forwardSummary << std::endl
<< " nblocks=" << numBlocks << std::endl);
@ -380,14 +401,8 @@ int main(int argc, char* argv[])
vtkm::Id3 globalSize;
vtkm::Id3 blocksPerDim;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
localBlockIndices.Allocate(blocksPerRank);
localBlockOrigins.Allocate(blocksPerRank);
localBlockSizes.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
// Read the pre-split data files
if (preSplitFiles)
@ -574,6 +589,11 @@ int main(int argc, char* argv[])
static_cast<ValueType>(offset[1]) };
const vtkm::Vec<ValueType, 2> v_spacing{ 1, 1 };
ds = dsb.Create(v_dims, v_origin, v_spacing);
vtkm::cont::CellSetStructured<2> cs;
cs.SetPointDimensions(v_dims);
cs.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cs.SetGlobalPointIndexStart(vtkm::Id2{ offset[0], offset[1] });
ds.SetCellSet(cs);
}
else
{
@ -586,6 +606,11 @@ int main(int argc, char* argv[])
static_cast<ValueType>(offset[2]) };
vtkm::Vec<ValueType, 3> v_spacing(1, 1, 1);
ds = dsb.Create(v_dims, v_origin, v_spacing);
vtkm::cont::CellSetStructured<3> cs;
cs.SetPointDimensions(v_dims);
cs.SetGlobalPointDimensions(globalSize);
cs.SetGlobalPointIndexStart(vtkm::Id3{ offset[0], offset[1], offset[2] });
ds.SetCellSet(cs);
}
ds.AddPointField("values", values);
// and add to partition
@ -596,14 +621,6 @@ int main(int argc, char* argv[])
vtkm::Id3{ static_cast<vtkm::Id>(blockIndex[0]),
static_cast<vtkm::Id>(blockIndex[1]),
static_cast<vtkm::Id>(nDims == 3 ? blockIndex[2] : 0) });
localBlockOriginsPortal.Set(blockNo,
vtkm::Id3{ static_cast<vtkm::Id>(offset[0]),
static_cast<vtkm::Id>(offset[1]),
static_cast<vtkm::Id>(nDims == 3 ? offset[2] : 0) });
localBlockSizesPortal.Set(blockNo,
vtkm::Id3{ static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(nDims == 3 ? dims[2] : 0) });
if (blockNo == 0)
{
@ -732,7 +749,6 @@ int main(int argc, char* argv[])
: vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(1));
std::cout << blocksPerDim << " " << globalSize << std::endl;
{
vtkm::Id lastDimSize =
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
@ -780,12 +796,12 @@ int main(int argc, char* argv[])
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
vtkm::Vec<ValueType, 2> spacing(1, 1);
ds = dsb.Create(vdims, origin, spacing);
vtkm::cont::CellSetStructured<2> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cs.SetGlobalPointIndexStart(vtkm::Id2{ 0, (blockStart / blockSliceSize) });
ds.SetCellSet(cs);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, blockIndex, 0));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, (blockStart / blockSliceSize), 0));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), currBlockSize, 0));
}
// 3D data
else
@ -797,14 +813,12 @@ int main(int argc, char* argv[])
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
ds = dsb.Create(vdims, origin, spacing);
vtkm::cont::CellSetStructured<3> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(globalSize);
cs.SetGlobalPointIndexStart(vtkm::Id3(0, 0, blockStart / blockSliceSize));
ds.SetCellSet(cs);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
currBlockSize));
}
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
@ -842,17 +856,13 @@ int main(int argc, char* argv[])
prevTime = currTime;
// Convert the mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeUniformDistributed filter(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes,
useBoundaryExtremaOnly,
useMarchingCubes,
augmentHierarchicalTree,
saveDotFiles,
timingsLogLevel,
treeLogLevel);
vtkm::filter::scalar_topology::ContourTreeUniformDistributed filter(timingsLogLevel,
treeLogLevel);
filter.SetBlockIndices(blocksPerDim, localBlockIndices);
filter.SetUseBoundaryExtremaOnly(useBoundaryExtremaOnly);
filter.SetUseMarchingCubes(useMarchingCubes);
filter.SetAugmentHierarchicalTree(augmentHierarchicalTree);
filter.SetSaveDotFiles(saveDotFiles);
filter.SetActiveField("values");
// Execute the contour tree analysis
@ -872,35 +882,56 @@ int main(int argc, char* argv[])
{
if (augmentHierarchicalTree)
{
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)
if (computeHierarchicalVolumetricBranchDecomposition)
{
auto ds = result.GetPartition(ds_no);
vtkm::worklet::contourtree_augmented::IdArrayType supernodes;
ds.GetField("Supernodes").GetData().AsArrayHandle(supernodes);
vtkm::worklet::contourtree_augmented::IdArrayType superarcs;
ds.GetField("Superarcs").GetData().AsArrayHandle(superarcs);
vtkm::worklet::contourtree_augmented::IdArrayType regularNodeGlobalIds;
ds.GetField("RegularNodeGlobalIds").GetData().AsArrayHandle(regularNodeGlobalIds);
vtkm::Id totalVolume = globalSize[0] * globalSize[1] * globalSize[2];
vtkm::worklet::contourtree_augmented::IdArrayType intrinsicVolume;
ds.GetField("IntrinsicVolume").GetData().AsArrayHandle(intrinsicVolume);
vtkm::worklet::contourtree_augmented::IdArrayType dependentVolume;
ds.GetField("DependentVolume").GetData().AsArrayHandle(dependentVolume);
vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter bd_filter;
auto bd_result = bd_filter.Execute(result);
std::string dumpVolumesString =
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<ValueType>::DumpVolumes(
supernodes,
superarcs,
regularNodeGlobalIds,
totalVolume,
intrinsicVolume,
dependentVolume);
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)
{
auto ds = bd_result.GetPartition(ds_no);
std::string branchDecompositionFileName = std::string("BranchDecomposition_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::string volumesFileName = std::string("TreeWithVolumes_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::ofstream treeStream(volumesFileName.c_str());
treeStream << dumpVolumesString;
std::ofstream treeStream(branchDecompositionFileName.c_str());
treeStream
<< vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::PrintBranches(
ds);
}
}
else
{
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)
{
auto ds = result.GetPartition(ds_no);
vtkm::worklet::contourtree_augmented::IdArrayType supernodes;
ds.GetField("Supernodes").GetData().AsArrayHandle(supernodes);
vtkm::worklet::contourtree_augmented::IdArrayType superarcs;
ds.GetField("Superarcs").GetData().AsArrayHandle(superarcs);
vtkm::worklet::contourtree_augmented::IdArrayType regularNodeGlobalIds;
ds.GetField("RegularNodeGlobalIds").GetData().AsArrayHandle(regularNodeGlobalIds);
vtkm::Id totalVolume = globalSize[0] * globalSize[1] * globalSize[2];
vtkm::worklet::contourtree_augmented::IdArrayType intrinsicVolume;
ds.GetField("IntrinsicVolume").GetData().AsArrayHandle(intrinsicVolume);
vtkm::worklet::contourtree_augmented::IdArrayType dependentVolume;
ds.GetField("DependentVolume").GetData().AsArrayHandle(dependentVolume);
std::string dumpVolumesString =
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<ValueType>::DumpVolumes(
supernodes,
superarcs,
regularNodeGlobalIds,
totalVolume,
intrinsicVolume,
dependentVolume);
std::string volumesFileName = std::string("TreeWithVolumes_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::ofstream treeStream(volumesFileName.c_str());
treeStream << dumpVolumesString;
}
}
}
else

@ -61,7 +61,7 @@
//==============================================================================
#include <stdio.h>
#include <vtkm/worklet/contourtree_distributed/TreeCompiler.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/TreeCompiler.h>
// main routine
int main(int argc, char** argv)

@ -0,0 +1,44 @@
#!/bin/sh
GTCT_DIR=${GTCT_DIR:-${HOME}/devel/parallel-peak-pruning/ContourTree/SweepAndMergeSerial/out}
RED=""
GREEN=""
NC=""
if [ -t 1 ]; then
# If stdout is a terminal, color Pass and FAIL green and red, respectively
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
NC=$(tput sgr0)
fi
echo "Removing previously generated files"
rm *.log *.dat
echo "Copying target file "$1 "into current directory"
filename=${1##*/}
fileroot=${filename%.txt}
cp $1 ${filename}
echo "Splitting data into "$2" x "$2" parts"
./split_data_2d.py ${filename} $2
rm ${filename}
echo "Running HACT"
n_parts=$(($2*$2))
# mpirun -np 4 --oversubscribe ./ContourTree_Distributed --vtkm-device Any --preSplitFiles --saveOutputData --augmentHierarchicalTree --computeVolumeBranchDecomposition --numBlocks=${n_parts} ${fileroot}_part_%d_of_${n_parts}.txt
mpirun -np 2 --oversubscribe ./ContourTree_Distributed --vtkm-device Any --preSplitFiles --saveOutputData --augmentHierarchicalTree --computeVolumeBranchDecomposition --numBlocks=${n_parts} ${fileroot}_part_%d_of_${n_parts}.txt
rm ${fileroot}_part_*_of_${n_parts}.txt
echo "Compiling Outputs"
sort -u BranchDecomposition_Rank_*.txt > outsort${fileroot}_$2x$2.txt
cat outsort${fileroot}_$2x$2.txt | ./BranchCompiler | sort > bcompile${fileroot}_$2x$2.txt
rm BranchDecomposition_Rank_*.txt outsort${fileroot}_$2x$2.txt
echo "Diffing"
echo diff bcompile${fileroot}_$2x$2.txt ${GTCT_DIR}/branch_decomposition_volume_hybrid_${fileroot}.txt
diff bcompile${fileroot}_$2x$2.txt ${GTCT_DIR}/branch_decomposition_volume_hybrid_${fileroot}.txt
if test $? -eq 0; then echo "${GREEN}Pass${NC}"; rm bcompile${fileroot}_$2x$2.txt; else echo "${RED}FAIL${NC}"; fi;
# echo "Generating Dot files"
# ./makedot.sh

@ -0,0 +1,99 @@
#!/bin/sh
mkdir -p out
DATA_DIR=${DATA_DIR:-${HOME}/devel/parallel-peak-pruning/Data/2D}
if [ ! -d $DATA_DIR ]; then
echo "Error: Directory $DATA_DIR does not exist!"
exit 1;
fi;
echo
echo "Starting Timing Runs"
echo
echo "8x9 Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/8x9test.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/8x9test.txt 4
# ./hact_test_branch_decomposition.sh $DATA_DIR/8x9test.txt 8
echo
echo "Vancouver Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vanc.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vanc.txt 4
# ./hact_test_branch_decomposition.sh $DATA_DIR/vanc.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vanc.txt 16
echo
echo "Vancouver SWSW Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSW.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSW.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSW.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSW.txt 16
echo
echo "Vancouver SWNW Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNW.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNW.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNW.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNW.txt 16
echo
echo "Vancouver SWSE Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSE.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSE.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSE.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWSE.txt 16
echo
echo "Vancouver SWNE Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNE.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNE.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNE.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSWNE.txt 16
echo
echo "Vancouver NE Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNE.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNE.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNE.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNE.txt 16
echo
echo "Vancouver NW Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNW.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNW.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNW.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverNW.txt 16
echo
echo "Vancouver SE Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSE.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSE.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSE.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSE.txt 16
echo
echo "Vancouver SW Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSW.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSW.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSW.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/vancouverSW.txt 16
echo
echo "Icefields Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 16
# ./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 32
# ./hact_test_branch_decomposition.sh $DATA_DIR/icefield.txt 64
echo
echo "GTOPO30 Full Tiny Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 16
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 32
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo_full_tiny.txt 64
echo
echo "GTOPO30 UK Tile Test Set"
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 2
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 4
./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 8
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 16
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 32
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 64
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 128
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 256
# ./hact_test_branch_decomposition.sh $DATA_DIR/gtopo30w020n40.txt 512
echo "Done"

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

@ -19,13 +19,14 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/interop/TransferToOpenGL.h>
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/filter/NewFilterField.h>
#include <vtkm/worklet/WorkletPointNeighborhood.h>
#include <vtkm/cont/Invoker.h>
@ -48,11 +49,6 @@
#include "LoadShaders.h"
struct GameOfLifePolicy : public vtkm::filter::PolicyBase<GameOfLifePolicy>
{
using FieldTypeList = vtkm::List<vtkm::UInt8, vtkm::Vec4ui_8>;
};
struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood
{
using CountingHandle = vtkm::cont::ArrayHandleCounting<vtkm::Id>;
@ -99,44 +95,33 @@ struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood
};
class GameOfLife : public vtkm::filter::FilterDataSet<GameOfLife>
class GameOfLife : public vtkm::filter::NewFilterField
{
public:
template <typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input,
vtkm::filter::PolicyBase<Policy> policy)
VTKM_CONT GameOfLife() { this->SetActiveField("state", vtkm::cont::Field::Association::Points); }
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override
{
vtkm::cont::ArrayHandle<vtkm::UInt8> state;
vtkm::cont::ArrayHandle<vtkm::UInt8> prevstate;
vtkm::cont::ArrayHandle<vtkm::Vec4ui_8> colors;
//get the coordinate system we are using for the 2D area
const vtkm::cont::UnknownCellSet cells = input.GetCellSet();
vtkm::cont::CellSetStructured<2> cells;
input.GetCellSet().AsCellSet(cells);
//get the previous state of the game
input.GetField("state", vtkm::cont::Field::Association::Points).GetData().CopyTo(prevstate);
this->GetFieldFromDataSet(input).GetData().AsArrayHandle(prevstate);
//Update the game state
this->Invoke(
UpdateLifeState{}, vtkm::filter::ApplyPolicyCellSet(cells, policy), prevstate, state, colors);
this->Invoke(UpdateLifeState{}, cells, prevstate, state, colors);
//save the results
vtkm::cont::DataSet output;
output.CopyStructure(input);
vtkm::cont::DataSet output =
this->CreateResultFieldPoint(input, this->GetActiveFieldName(), state);
output.AddField(vtkm::cont::make_FieldPoint("colors", colors));
output.AddField(vtkm::cont::make_FieldPoint("state", state));
return output;
}
template <typename DerivedPolicy>
VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet&,
const vtkm::cont::Field&,
vtkm::filter::PolicyBase<DerivedPolicy>)
{
return false;
}
};
struct UploadData
@ -346,7 +331,7 @@ int main(int argc, char** argv)
glutDisplayFunc([]() {
const vtkm::Float32 c = static_cast<vtkm::Float32>(gTimer.GetElapsedTime());
vtkm::cont::DataSet oData = gFilter->Execute(*gData, GameOfLifePolicy());
vtkm::cont::DataSet oData = gFilter->Execute(*gData);
gRenderer->render(oData);
glutSwapBuffers();

@ -10,8 +10,7 @@
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/filter/CreateResult.h>
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/NewFilterField.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
@ -23,58 +22,56 @@
#include <cstdlib>
#include <iostream>
namespace vtkm
{
namespace worklet
namespace hello_worklet_example
{
struct HelloWorklet : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn inVector, FieldOut outMagnitude);
VTKM_EXEC void operator()(const vtkm::Vec3f& inVector, vtkm::FloatDefault& outMagnitude) const
template <typename T>
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& inVector, T& outMagnitude) const
{
outMagnitude = vtkm::Magnitude(inVector);
}
};
}
} // namespace vtkm::worklet
} // namespace hello_worklet_example
namespace vtkm
{
namespace filter
{
class HelloField : public vtkm::filter::FilterField<HelloField>
class HelloField : public vtkm::filter::NewFilterField
{
public:
// Specify that this filter operates on 3-vectors
using SupportedTypes = vtkm::TypeListFieldVec3;
template <typename FieldType, typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet,
const FieldType& inField,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<Policy>)
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet)
{
VTKM_IS_ARRAY_HANDLE(FieldType);
// Input field
vtkm::cont::Field inField = this->GetFieldFromDataSet(inDataSet);
//construct our output
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outField;
// Holder for output
vtkm::cont::UnknownArrayHandle outArray;
//construct our invoker to launch worklets
vtkm::worklet::HelloWorklet mag;
this->Invoke(mag, inField, outField); //launch mag worklets
hello_worklet_example::HelloWorklet mag;
auto resolveType = [&](const auto& inputArray) {
// use std::decay to remove const ref from the decltype of concrete.
using T = typename std::decay_t<decltype(inputArray)>::ValueType::ComponentType;
vtkm::cont::ArrayHandle<T> result;
this->Invoke(mag, inputArray, result);
outArray = result;
};
//construct output field information
if (this->GetOutputFieldName().empty())
this->CastAndCallVecField<3>(inField, resolveType);
std::string outFieldName = this->GetOutputFieldName();
if (outFieldName.empty())
{
this->SetOutputFieldName(fieldMetadata.GetName() + "_magnitude");
outFieldName = inField.GetName() + "_magnitude";
}
//return the result, which is the input data with the computed field added to it
return vtkm::filter::CreateResult(
inDataSet, outField, this->GetOutputFieldName(), fieldMetadata);
return this->CreateResultField(inDataSet, outFieldName, inField.GetAssociation(), outArray);
}
};
}

@ -13,9 +13,9 @@ project(Histogram CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_MPI)
add_executable(Histogram Histogram.cxx HistogramMPI.h HistogramMPI.hxx)
add_executable(Histogram Histogram.cxx HistogramMPI.h HistogramMPI.cxx)
target_link_libraries(Histogram PRIVATE vtkm_filter MPI::MPI_CXX)
vtkm_add_target_information(Histogram
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Histogram.cxx)
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES HistogramMPI.cxx)
endif()

@ -64,9 +64,8 @@ int main(int argc, char* argv[])
// tell VTK-m the communicator to use.
vtkm::cont::EnvironmentTracker::SetCommunicator(world);
int rank, size;
MPI_Comm_rank(vtkmdiy::mpi::mpi_cast(world.handle()), &rank);
MPI_Comm_size(vtkmdiy::mpi::mpi_cast(world.handle()), &size);
int rank = world.rank();
int size = world.size();
if (argc != 2)
{

@ -8,6 +8,8 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include "HistogramMPI.h"
#include <vtkm/filter/density_estimate/worklet/FieldHistogram.h>
#include <vtkm/cont/Algorithm.h>
@ -102,53 +104,69 @@ public:
} // namespace detail
//-----------------------------------------------------------------------------
inline VTKM_CONT HistogramMPI::HistogramMPI()
: NumberOfBins(10)
, BinDelta(0)
, ComputedRange()
, Range()
VTKM_CONT vtkm::cont::DataSet HistogramMPI::DoExecute(const vtkm::cont::DataSet& input)
{
this->SetOutputFieldName("histogram");
}
const auto& fieldArray = this->GetFieldFromDataSet(input).GetData();
//-----------------------------------------------------------------------------
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet HistogramMPI::DoExecute(
const vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata&,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
vtkm::cont::ArrayHandle<vtkm::Id> binArray;
T delta;
vtkm::worklet::FieldHistogram worklet;
if (this->ComputedRange.IsNonEmpty())
if (!this->InExecutePartitions)
{
worklet.Run(field,
// Handle initialization that would be done in PreExecute if the data set had partitions.
if (this->Range.IsNonEmpty())
{
this->ComputedRange = this->Range;
}
else
{
auto handle = vtkm::cont::FieldRangeGlobalCompute(
input, this->GetActiveFieldName(), this->GetActiveFieldAssociation());
if (handle.GetNumberOfValues() != 1)
{
throw vtkm::cont::ErrorFilterExecution("expecting scalar field.");
}
this->ComputedRange = handle.ReadPortal().Get(0);
}
}
vtkm::cont::ArrayHandle<vtkm::Id> binArray;
auto resolveType = [&](const auto& concrete) {
using T = typename std::decay_t<decltype(concrete)>::ValueType;
T delta;
vtkm::worklet::FieldHistogram worklet;
worklet.Run(concrete,
this->NumberOfBins,
static_cast<T>(this->ComputedRange.Min),
static_cast<T>(this->ComputedRange.Max),
delta,
binArray);
}
else
{
worklet.Run(field, this->NumberOfBins, this->ComputedRange, delta, binArray);
}
this->BinDelta = static_cast<vtkm::Float64>(delta);
this->BinDelta = static_cast<vtkm::Float64>(delta);
};
fieldArray
.CastAndCallForTypesWithFloatFallback<vtkm::TypeListFieldScalar, VTKM_DEFAULT_STORAGE_LIST>(
resolveType);
vtkm::cont::DataSet output;
vtkm::cont::Field rfield(
this->GetOutputFieldName(), vtkm::cont::Field::Association::WholeMesh, binArray);
output.AddField(rfield);
output.AddField(
{ this->GetOutputFieldName(), vtkm::cont::Field::Association::WholeDataSet, binArray });
// The output is a "summary" of the input, no need to map fields
return output;
}
VTKM_CONT vtkm::cont::PartitionedDataSet HistogramMPI::DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& input)
{
this->PreExecute(input);
auto result = this->NewFilter::DoExecutePartitions(input);
this->PostExecute(input, result);
return result;
}
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::PartitionedDataSet& input)
{
if (this->Range.IsNonEmpty())
{
@ -167,10 +185,8 @@ inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::PartitionedData
}
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void HistogramMPI::PostExecute(const vtkm::cont::PartitionedDataSet&,
vtkm::cont::PartitionedDataSet& result,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
vtkm::cont::PartitionedDataSet& result)
{
// iterate and compute HistogramMPI for each local block.
detail::DistributedHistogram helper(result.GetNumberOfPartitions());
@ -182,7 +198,7 @@ inline VTKM_CONT void HistogramMPI::PostExecute(const vtkm::cont::PartitionedDat
vtkm::cont::DataSet output;
vtkm::cont::Field rfield(this->GetOutputFieldName(),
vtkm::cont::Field::Association::WholeMesh,
vtkm::cont::Field::Association::WholeDataSet,
helper.ReduceAll(this->NumberOfBins));
output.AddField(rfield);

@ -10,7 +10,7 @@
#ifndef vtk_m_examples_histogram_HistogramMPI_h
#define vtk_m_examples_histogram_HistogramMPI_h
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/NewFilterField.h>
namespace example
{
@ -19,7 +19,7 @@ namespace example
///
/// Construct a HistogramMPI with a default of 10 bins.
///
class HistogramMPI : public vtkm::filter::FilterField<HistogramMPI>
class HistogramMPI : public vtkm::filter::NewFilterField
{
public:
//currently the HistogramMPI filter only works on scalar data.
@ -29,7 +29,7 @@ public:
//Construct a HistogramMPI with a default of 10 bins
VTKM_CONT
HistogramMPI();
HistogramMPI() { this->SetOutputFieldName("histogram"); }
VTKM_CONT
void SetNumberOfBins(vtkm::Id count) { this->NumberOfBins = count; }
@ -37,7 +37,7 @@ public:
VTKM_CONT
vtkm::Id GetNumberOfBins() const { return this->NumberOfBins; }
//@{
///@{
/// Get/Set the range to use to generate the HistogramMPI. If range is set to
/// empty, the field's global range (computed using `vtkm::cont::FieldRangeGlobalCompute`)
/// will be used.
@ -46,7 +46,7 @@ public:
VTKM_CONT
const vtkm::Range& GetRange() const { return this->Range; }
//@}
///@}
/// Returns the bin delta of the last computed field.
VTKM_CONT
@ -58,34 +58,27 @@ public:
VTKM_CONT
vtkm::Range GetComputedRange() const { return this->ComputedRange; }
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
protected:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override;
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& input) override;
//@{
///@{
/// when operating on vtkm::cont::PartitionedDataSet, we
/// want to do processing across ranks as well. Just adding pre/post handles
/// for the same does the trick.
template <typename DerivedPolicy>
VTKM_CONT void PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
template <typename DerivedPolicy>
VTKM_CONT void PreExecute(const vtkm::cont::PartitionedDataSet& input);
VTKM_CONT void PostExecute(const vtkm::cont::PartitionedDataSet& input,
vtkm::cont::PartitionedDataSet& output,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
//@}
vtkm::cont::PartitionedDataSet& output);
///@}
private:
vtkm::Id NumberOfBins;
vtkm::Float64 BinDelta;
vtkm::Id NumberOfBins = 10;
vtkm::Float64 BinDelta = 0;
vtkm::Range ComputedRange;
vtkm::Range Range;
bool InExecutePartitions = false;
};
} // namespace example
#include "HistogramMPI.hxx"
#endif // vtk_m_filter_Histogram_h

@ -17,7 +17,7 @@
#include <vtkm/cont/DataSetBuilderRectilinear.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/Lagrangian.h>
#include <vtkm/filter/flow/Lagrangian.h>
using namespace std;
@ -79,7 +79,7 @@ int main(int argc, char** argv)
vtkm::cont::InitializeOptions::DefaultAnyDevice | vtkm::cont::InitializeOptions::Strict;
vtkm::cont::Initialize(argc, argv, opts);
vtkm::filter::Lagrangian lagrangianFilter;
vtkm::filter::flow::Lagrangian lagrangianFilter;
lagrangianFilter.SetResetParticles(true);
vtkm::Float32 stepSize = 0.01f;
lagrangianFilter.SetStepSize(stepSize);

@ -27,11 +27,3 @@ find_package(VTKm REQUIRED QUIET)
add_executable(MeshQuality MeshQuality.cxx)
target_link_libraries(MeshQuality PRIVATE vtkm_filter vtkm_io)
if(TARGET vtkm::tbb)
target_compile_definitions(MeshQuality PRIVATE BUILDING_TBB_VERSION)
endif()
vtkm_add_target_information(MeshQuality
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES MeshQuality.cxx)

@ -8,11 +8,251 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#define vtk_m_examples_multibackend_MultiDeviceGradient_cxx
#include "MultiDeviceGradient.h"
#include "MultiDeviceGradient.hxx"
template vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>&);
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/openmp/DeviceAdapterOpenMP.h>
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
#include <vtkm/filter/vector_analysis/Gradient.h>
namespace
{
void process_partition_tbb(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to TBB.
//This makes sure that any vtkm::filters used by our
//task operate only on TBB. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagTBB{});
while (queue.hasTasks())
{
//Step 2. Get the task to run on TBB
auto task = queue.pop();
//Step 3. Run the task on TBB. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
}
}
void process_partition_openMP(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to openMP.
//This makes sure that any vtkm::filters used by our
//task operate only on openMP. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
while (queue.hasTasks())
{
//Step 2. Get the task to run on openMP
auto task = queue.pop();
//Step 3. Run the task on openMP. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on openMP (" << std::this_thread::get_id() << ")"
<< std::endl;
}
}
void process_partition_cuda(RuntimeTaskQueue& queue, int gpuId)
{
//Step 1. Set the device adapter to this thread to cuda.
//This makes sure that any vtkm::filters used by our
//task operate only on cuda. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagCuda{});
(void)gpuId;
while (queue.hasTasks())
{
//Step 2. Get the task to run on cuda
auto task = queue.pop();
//Step 3. Run the task on cuda. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on cuda (" << std::this_thread::get_id() << ")" << std::endl;
}
}
} //namespace
//-----------------------------------------------------------------------------
VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
: ComputePointGradient(false)
, Queue()
, Workers()
{
//Step 1. Determine the number of workers we want
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
const bool runOnCuda = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagCuda{});
const bool runOnOpenMP = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagOpenMP{});
const bool runOnTbb = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagTBB{});
//Note currently the virtual implementation has some issues
//In a multi-threaded environment only cuda can be used or
//all SMP backends ( Serial, TBB, OpenMP ).
//Once this issue is resolved we can enable CUDA + TBB in
//this example
//Step 2. Launch workers that will use cuda (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
if (runOnCuda)
{
std::cout << "adding cuda workers" << std::endl;
try
{
vtkm::Id gpu_count = 0;
vtkm::cont::RuntimeDeviceInformation{}
.GetRuntimeConfiguration(vtkm::cont::DeviceAdapterTagCuda{})
.GetMaxDevices(gpu_count);
for (int i = 0; i < gpu_count; ++i)
{
//The number of workers per GPU is purely arbitrary currently,
//but in general we want multiple of them so we can overlap compute
//and transfer
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
}
}
catch (const vtkm::cont::ErrorBadDevice& err)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Error getting CudaDeviceCount: " << err.GetMessage());
}
}
//Step 3. Launch a worker that will use openMP (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
else if (runOnOpenMP)
{
std::cout << "adding a openMP worker" << std::endl;
this->Workers.emplace_back(std::bind(process_partition_openMP, std::ref(this->Queue)));
}
//Step 4. Launch a worker that will use tbb (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
else if (runOnTbb)
{
std::cout << "adding a tbb worker" << std::endl;
this->Workers.emplace_back(std::bind(process_partition_tbb, std::ref(this->Queue)));
}
}
//-----------------------------------------------------------------------------
VTKM_CONT MultiDeviceGradient::~MultiDeviceGradient()
{
this->Queue.shutdown();
//shutdown all workers
for (auto&& thread : this->Workers)
{
thread.join();
}
}
//-----------------------------------------------------------------------------
VTKM_CONT vtkm::cont::PartitionedDataSet MultiDeviceGradient::DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& pds)
{
//Step 1. Say that we have no more to submit for this PartitionedDataSet
//This is needed to happen for each execute as we want to support
//the same filter being used for multiple inputs
this->Queue.reset();
//Step 2. Construct the PartitionedDataSet we are going to fill. The size
//signature to PartitionedDataSet just reserves size
vtkm::cont::PartitionedDataSet output;
output.AppendPartitions(
std::vector<vtkm::cont::DataSet>(static_cast<size_t>(pds.GetNumberOfPartitions())));
vtkm::cont::PartitionedDataSet* outPtr = &output;
//Step 3. Construct the filter we want to run on each partition
vtkm::filter::vector_analysis::Gradient gradient;
gradient.SetComputePointGradient(this->GetComputePointGradient());
gradient.SetActiveField(this->GetActiveFieldName());
//Step 3b. Post 1 partition up as work and block until it is
//complete. This is needed as currently constructing the virtual
//Point Coordinates is not thread safe.
auto partition = pds.cbegin();
{
vtkm::cont::DataSet input = *partition;
this->Queue.push( //build a lambda that is the work to do
[=]() {
vtkm::filter::vector_analysis::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input);
outPtr->ReplacePartition(0, result);
});
this->Queue.waitForAllTasksToComplete();
partition++;
}
vtkm::Id index = 1;
for (; partition != pds.cend(); ++partition)
{
vtkm::cont::DataSet input = *partition;
//Step 4. For each input partition construct a lambda
//and add it to the queue for workers to take. This
//will allows us to have multiple works execute in a non
//blocking manner
this->Queue.push( //build a lambda that is the work to do
[=]() {
vtkm::filter::vector_analysis::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input);
outPtr->ReplacePartition(index, result);
});
index++;
}
// Step 5. Wait on all workers to finish
this->Queue.waitForAllTasksToComplete();
return output;
}
VTKM_CONT vtkm::cont::DataSet MultiDeviceGradient::DoExecute(const vtkm::cont::DataSet& inData)
{
vtkm::cont::PartitionedDataSet outData = this->Execute(vtkm::cont::PartitionedDataSet(inData));
VTKM_ASSERT(outData.GetNumberOfPartitions() == 1);
return outData.GetPartition(0);
}

@ -10,7 +10,7 @@
#ifndef vtk_m_examples_multibackend_MultiDeviceGradient_h
#define vtk_m_examples_multibackend_MultiDeviceGradient_h
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/NewFilterField.h>
#include "TaskQueue.h"
@ -22,11 +22,9 @@ using RuntimeTaskQueue = TaskQueue<std::function<void()>>;
///
/// The Policy used with MultiDeviceGradient must include the TBB and CUDA
/// backends.
class MultiDeviceGradient : public vtkm::filter::FilterField<MultiDeviceGradient>
class MultiDeviceGradient : public vtkm::filter::NewFilterField
{
public:
using SupportedTypes = vtkm::List<vtkm::Float32, vtkm::Float64, vtkm::Vec3f_32, vtkm::Vec3f_64>;
//Construct a MultiDeviceGradient and worker pool
VTKM_CONT
MultiDeviceGradient();
@ -43,10 +41,12 @@ public:
/// Will submit each block to a work queue that the threads will
/// pull work from
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::PartitionedDataSet PrepareForExecution(
const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& inData) override;
// All filters must override this method. Our implementation will just wrap this in
// a partitioned data set.
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inData) override;
private:
bool ComputePointGradient;
@ -54,10 +54,4 @@ private:
std::vector<std::thread> Workers;
};
#ifndef vtk_m_examples_multibackend_MultiDeviceGradient_cxx
extern template vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>&);
#endif
#endif

@ -1,252 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/openmp/DeviceAdapterOpenMP.h>
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
#include <vtkm/filter/vector_analysis/Gradient.h>
namespace
{
void process_partition_tbb(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to TBB.
//This makes sure that any vtkm::filters used by our
//task operate only on TBB. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagTBB{});
while (queue.hasTasks())
{
//Step 2. Get the task to run on TBB
auto task = queue.pop();
//Step 3. Run the task on TBB. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
}
}
void process_partition_openMP(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to openMP.
//This makes sure that any vtkm::filters used by our
//task operate only on openMP. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
while (queue.hasTasks())
{
//Step 2. Get the task to run on openMP
auto task = queue.pop();
//Step 3. Run the task on openMP. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on openMP (" << std::this_thread::get_id() << ")"
<< std::endl;
}
}
void process_partition_cuda(RuntimeTaskQueue& queue, int gpuId)
{
//Step 1. Set the device adapter to this thread to cuda.
//This makes sure that any vtkm::filters used by our
//task operate only on cuda. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagCuda{});
(void)gpuId;
while (queue.hasTasks())
{
//Step 2. Get the task to run on cuda
auto task = queue.pop();
//Step 3. Run the task on cuda. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
{
task();
}
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on cuda (" << std::this_thread::get_id() << ")" << std::endl;
}
}
} //namespace
//-----------------------------------------------------------------------------
VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
: ComputePointGradient(false)
, Queue()
, Workers()
{
//Step 1. Determine the number of workers we want
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
const bool runOnCuda = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagCuda{});
const bool runOnOpenMP = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagOpenMP{});
const bool runOnTbb = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagTBB{});
//Note currently the virtual implementation has some issues
//In a multi-threaded environment only cuda can be used or
//all SMP backends ( Serial, TBB, OpenMP ).
//Once this issue is resolved we can enable CUDA + TBB in
//this example
//Step 2. Launch workers that will use cuda (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
if (runOnCuda)
{
std::cout << "adding cuda workers" << std::endl;
try
{
vtkm::Id gpu_count = 0;
vtkm::cont::RuntimeDeviceInformation{}
.GetRuntimeConfiguration(vtkm::cont::DeviceAdapterTagCuda{})
.GetMaxDevices(gpu_count);
for (int i = 0; i < gpu_count; ++i)
{
//The number of workers per GPU is purely arbitrary currently,
//but in general we want multiple of them so we can overlap compute
//and transfer
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
}
}
catch (const vtkm::cont::ErrorBadDevice& err)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Error getting CudaDeviceCount: " << err.GetMessage());
}
}
//Step 3. Launch a worker that will use openMP (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
else if (runOnOpenMP)
{
std::cout << "adding a openMP worker" << std::endl;
this->Workers.emplace_back(std::bind(process_partition_openMP, std::ref(this->Queue)));
}
//Step 4. Launch a worker that will use tbb (if enabled).
//The threads share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
else if (runOnTbb)
{
std::cout << "adding a tbb worker" << std::endl;
this->Workers.emplace_back(std::bind(process_partition_tbb, std::ref(this->Queue)));
}
}
//-----------------------------------------------------------------------------
VTKM_CONT MultiDeviceGradient::~MultiDeviceGradient()
{
this->Queue.shutdown();
//shutdown all workers
for (auto&& thread : this->Workers)
{
thread.join();
}
}
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution(
const vtkm::cont::PartitionedDataSet& pds,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
//Step 1. Say that we have no more to submit for this PartitionedDataSet
//This is needed to happen for each execute as we want to support
//the same filter being used for multiple inputs
this->Queue.reset();
//Step 2. Construct the PartitionedDataSet we are going to fill. The size
//signature to PartitionedDataSet just reserves size
vtkm::cont::PartitionedDataSet output;
output.AppendPartitions(
std::vector<vtkm::cont::DataSet>(static_cast<size_t>(pds.GetNumberOfPartitions())));
vtkm::cont::PartitionedDataSet* outPtr = &output;
//Step 3. Construct the filter we want to run on each partition
vtkm::filter::vector_analysis::Gradient gradient;
gradient.SetComputePointGradient(this->GetComputePointGradient());
gradient.SetActiveField(this->GetActiveFieldName());
//Step 3b. Post 1 partition up as work and block until it is
//complete. This is needed as currently constructing the virtual
//Point Coordinates is not thread safe.
auto partition = pds.cbegin();
{
vtkm::cont::DataSet input = *partition;
this->Queue.push( //build a lambda that is the work to do
[=]() {
vtkm::filter::vector_analysis::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input);
outPtr->ReplacePartition(0, result);
});
this->Queue.waitForAllTasksToComplete();
partition++;
}
vtkm::Id index = 1;
for (; partition != pds.cend(); ++partition)
{
vtkm::cont::DataSet input = *partition;
//Step 4. For each input partition construct a lambda
//and add it to the queue for workers to take. This
//will allows us to have multiple works execute in a non
//blocking manner
this->Queue.push( //build a lambda that is the work to do
[=]() {
vtkm::filter::vector_analysis::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input);
outPtr->ReplacePartition(index, result);
});
index++;
}
// Step 5. Wait on all workers to finish
this->Queue.waitForAllTasksToComplete();
return output;
}

@ -15,6 +15,3 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Oscillator Oscillator.cxx)
target_link_libraries(Oscillator PRIVATE vtkm_source)
vtkm_add_target_information(Oscillator
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Oscillator.cxx)

@ -9,19 +9,13 @@
//============================================================================
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vtkm/Math.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/source/Oscillator.h>
#if !defined(_WIN32) || defined(__CYGWIN__)

@ -14,10 +14,4 @@ project(ParticleAdvection CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Particle_Advection ParticleAdvection.cxx)
target_link_libraries(Particle_Advection PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Particle_Advection
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES ParticleAdvection.cxx)
if(TARGET vtkm::tbb)
target_compile_definitions(Particle_Advection PRIVATE BUILDING_TBB_VERSION)
endif()
target_link_libraries(Particle_Advection PRIVATE vtkm_filter_flow vtkm_io)

@ -8,9 +8,10 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/Particle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/filter/Streamline.h>
#include <vtkm/filter/flow/Streamline.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
@ -74,7 +75,7 @@ int main(int argc, char** argv)
auto seedArray = vtkm::cont::make_ArrayHandle(seeds, vtkm::CopyFlag::Off);
//compute streamlines
vtkm::filter::Streamline streamline;
vtkm::filter::flow::Streamline streamline;
streamline.SetStepSize(stepSize);
streamline.SetNumberOfSteps(numSteps);

@ -13,8 +13,8 @@ project(PolyLineArchimedeanHelix CXX)
find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_RENDERING)
add_executable(PolyLineArchimedeanHelix PolyLineArchimedeanHelix.cxx)
vtkm_add_target_information(PolyLineArchimedeanHelix
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES PolyLineArchimedeanHelix.cxx)
target_link_libraries(PolyLineArchimedeanHelix PRIVATE vtkm_filter vtkm_rendering)
vtkm_add_target_information(PolyLineArchimedeanHelix
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES PolyLineArchimedeanHelix.cxx)
endif()

@ -12,7 +12,7 @@ project(RedistributePoints CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h)
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h main.cxx)
target_link_libraries(RedistributePoints PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(RedistributePoints
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS

@ -8,53 +8,228 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Initialize.h>
#include "RedistributePoints.h"
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/ImplicitFunction.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Serialization.h>
#include <vtkm/filter/entity_extraction/ExtractPoints.h>
#include <vtkm/thirdparty/diy/diy.h>
#include "RedistributePoints.h"
#include <sstream>
using std::cout;
using std::endl;
int main(int argc, char* argv[])
namespace example
{
// Process vtk-m general args
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
auto config = vtkm::cont::Initialize(argc, argv, opts);
vtkmdiy::mpi::environment env(argc, argv);
vtkmdiy::mpi::communicator comm;
vtkm::cont::EnvironmentTracker::SetCommunicator(comm);
namespace internal
{
if (argc != 3)
{
cout << "Usage: " << endl
<< "$ " << argv[0] << " [options] <input-vtk-file> <output-file-prefix>" << endl;
cout << config.Usage << endl;
return EXIT_FAILURE;
}
vtkm::cont::DataSet input;
if (comm.rank() == 0)
{
vtkm::io::VTKDataSetReader reader(argv[1]);
input = reader.ReadDataSet();
}
example::RedistributePoints redistributor;
auto output = redistributor.Execute(input);
std::ostringstream str;
str << argv[2] << "-" << comm.rank() << ".vtk";
vtkm::io::VTKDataSetWriter writer(str.str());
writer.WriteDataSet(output);
return EXIT_SUCCESS;
static vtkmdiy::ContinuousBounds convert(const vtkm::Bounds& bds)
{
vtkmdiy::ContinuousBounds result(3);
result.min[0] = static_cast<float>(bds.X.Min);
result.min[1] = static_cast<float>(bds.Y.Min);
result.min[2] = static_cast<float>(bds.Z.Min);
result.max[0] = static_cast<float>(bds.X.Max);
result.max[1] = static_cast<float>(bds.Y.Max);
result.max[2] = static_cast<float>(bds.Z.Max);
return result;
}
template <typename FilterType>
class Redistributor
{
const vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds>& Decomposer;
const FilterType& Filter;
vtkm::cont::DataSet Extract(const vtkm::cont::DataSet& input,
const vtkmdiy::ContinuousBounds& bds) const
{
// extract points
vtkm::Box box(bds.min[0], bds.max[0], bds.min[1], bds.max[1], bds.min[2], bds.max[2]);
vtkm::filter::entity_extraction::ExtractPoints extractor;
extractor.SetCompactPoints(true);
extractor.SetImplicitFunction(box);
return extractor.Execute(input);
}
class ConcatenateFields
{
public:
explicit ConcatenateFields(vtkm::Id totalSize)
: TotalSize(totalSize)
, CurrentIdx(0)
{
}
void Append(const vtkm::cont::Field& field)
{
VTKM_ASSERT(this->CurrentIdx + field.GetNumberOfValues() <= this->TotalSize);
if (this->Field.GetNumberOfValues() == 0)
{
// Copy metadata
this->Field = field;
// Reset array
this->Field.SetData(field.GetData().NewInstanceBasic());
// Preallocate array
this->Field.GetData().Allocate(this->TotalSize);
}
else
{
VTKM_ASSERT(this->Field.GetName() == field.GetName() &&
this->Field.GetAssociation() == field.GetAssociation());
}
field.GetData().CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
Appender{}, this->Field, this->CurrentIdx);
this->CurrentIdx += field.GetNumberOfValues();
}
const vtkm::cont::Field& GetResult() const { return this->Field; }
private:
struct Appender
{
template <typename T, typename S>
void operator()(const vtkm::cont::ArrayHandle<T, S>& data,
vtkm::cont::Field& field,
vtkm::Id currentIdx) const
{
vtkm::cont::ArrayHandle<T> farray =
field.GetData().template AsArrayHandle<vtkm::cont::ArrayHandle<T>>();
vtkm::cont::Algorithm::CopySubRange(data, 0, data.GetNumberOfValues(), farray, currentIdx);
}
};
vtkm::Id TotalSize;
vtkm::Id CurrentIdx;
vtkm::cont::Field Field;
};
public:
Redistributor(const vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds>& decomposer,
const FilterType& filter)
: Decomposer(decomposer)
, Filter(filter)
{
}
void operator()(vtkm::cont::DataSet* block, const vtkmdiy::ReduceProxy& rp) const
{
if (rp.in_link().size() == 0)
{
if (block->GetNumberOfCoordinateSystems() > 0)
{
for (int cc = 0; cc < rp.out_link().size(); ++cc)
{
auto target = rp.out_link().target(cc);
// let's get the bounding box for the target block.
vtkmdiy::ContinuousBounds bds(3);
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));
}
// clear our dataset.
*block = vtkm::cont::DataSet();
}
}
else
{
vtkm::Id numValues = 0;
std::vector<vtkm::cont::DataSet> receives;
for (int cc = 0; cc < rp.in_link().size(); ++cc)
{
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);
numValues += receives.back().GetCoordinateSystem(0).GetNumberOfPoints();
}
}
*block = vtkm::cont::DataSet();
if (receives.size() == 1)
{
*block = receives[0];
}
else if (receives.size() > 1)
{
ConcatenateFields concatCoords(numValues);
for (const auto& ds : receives)
{
concatCoords.Append(ds.GetCoordinateSystem(0));
}
block->AddCoordinateSystem(vtkm::cont::CoordinateSystem(
concatCoords.GetResult().GetName(), concatCoords.GetResult().GetData()));
for (vtkm::IdComponent i = 0; i < receives[0].GetNumberOfFields(); ++i)
{
ConcatenateFields concatField(numValues);
for (const auto& ds : receives)
{
concatField.Append(ds.GetField(i));
}
block->AddField(concatField.GetResult());
}
}
}
}
};
} // namespace example::internal
VTKM_CONT vtkm::cont::PartitionedDataSet RedistributePoints::DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& input)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
// let's first get the global bounds of the domain
vtkm::Bounds gbounds = vtkm::cont::BoundsGlobalCompute(input);
vtkm::cont::AssignerPartitionedDataSet assigner(input.GetNumberOfPartitions());
vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds> decomposer(
/*dim*/ 3, internal::convert(gbounds), assigner.nblocks());
vtkmdiy::Master master(
comm,
/*threads*/ 1,
/*limit*/ -1,
[]() -> void* { return new vtkm::cont::DataSet(); },
[](void* ptr) { delete static_cast<vtkm::cont::DataSet*>(ptr); });
decomposer.decompose(comm.rank(), assigner, master);
assert(static_cast<vtkm::Id>(master.size()) == input.GetNumberOfPartitions());
// let's populate local blocks
master.foreach ([&input](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink& proxy) {
auto lid = proxy.master()->lid(proxy.gid());
*ds = input.GetPartition(lid);
});
internal::Redistributor<RedistributePoints> redistributor(decomposer, *this);
vtkmdiy::all_to_all(master, assigner, redistributor, /*k=*/2);
vtkm::cont::PartitionedDataSet result;
master.foreach ([&result](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink&) {
result.AppendPartition(*ds);
});
return result;
}
vtkm::cont::DataSet RedistributePoints::DoExecute(const vtkm::cont::DataSet&)
{
throw vtkm::cont::ErrorBadType("RedistributePoints requires PartitionedDataSet.");
}
} // namespace example

@ -7,238 +7,28 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef example_RedistributePoints_h
#define example_RedistributePoints_h
#include <vtkm/ImplicitFunction.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Serialization.h>
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/entity_extraction/ExtractPoints.h>
#include <vtkm/thirdparty/diy/diy.h>
#include <vtkm/filter/NewFilter.h>
namespace example
{
namespace internal
{
static vtkmdiy::ContinuousBounds convert(const vtkm::Bounds& bds)
{
vtkmdiy::ContinuousBounds result(3);
result.min[0] = static_cast<float>(bds.X.Min);
result.min[1] = static_cast<float>(bds.Y.Min);
result.min[2] = static_cast<float>(bds.Z.Min);
result.max[0] = static_cast<float>(bds.X.Max);
result.max[1] = static_cast<float>(bds.Y.Max);
result.max[2] = static_cast<float>(bds.Z.Max);
return result;
}
template <typename FilterType>
class Redistributor
{
const vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds>& Decomposer;
const FilterType& Filter;
vtkm::cont::DataSet Extract(const vtkm::cont::DataSet& input,
const vtkmdiy::ContinuousBounds& bds) const
{
// extract points
vtkm::Box box(bds.min[0], bds.max[0], bds.min[1], bds.max[1], bds.min[2], bds.max[2]);
vtkm::filter::entity_extraction::ExtractPoints extractor;
extractor.SetCompactPoints(true);
extractor.SetImplicitFunction(box);
return extractor.Execute(input);
}
class ConcatenateFields
{
public:
explicit ConcatenateFields(vtkm::Id totalSize)
: TotalSize(totalSize)
, CurrentIdx(0)
{
}
void Append(const vtkm::cont::Field& field)
{
VTKM_ASSERT(this->CurrentIdx + field.GetNumberOfValues() <= this->TotalSize);
if (this->Field.GetNumberOfValues() == 0)
{
// Copy metadata
this->Field = field;
// Reset array
this->Field.SetData(field.GetData().NewInstanceBasic());
// Preallocate array
this->Field.GetData().Allocate(this->TotalSize);
}
else
{
VTKM_ASSERT(this->Field.GetName() == field.GetName() &&
this->Field.GetAssociation() == field.GetAssociation());
}
field.GetData().CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
Appender{}, this->Field, this->CurrentIdx);
this->CurrentIdx += field.GetNumberOfValues();
}
const vtkm::cont::Field& GetResult() const { return this->Field; }
private:
struct Appender
{
template <typename T, typename S>
void operator()(const vtkm::cont::ArrayHandle<T, S>& data,
vtkm::cont::Field& field,
vtkm::Id currentIdx) const
{
vtkm::cont::ArrayHandle<T> farray =
field.GetData().template AsArrayHandle<vtkm::cont::ArrayHandle<T>>();
vtkm::cont::Algorithm::CopySubRange(data, 0, data.GetNumberOfValues(), farray, currentIdx);
}
};
vtkm::Id TotalSize;
vtkm::Id CurrentIdx;
vtkm::cont::Field Field;
};
public:
Redistributor(const vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds>& decomposer,
const FilterType& filter)
: Decomposer(decomposer)
, Filter(filter)
{
}
void operator()(vtkm::cont::DataSet* block, const vtkmdiy::ReduceProxy& rp) const
{
if (rp.in_link().size() == 0)
{
if (block->GetNumberOfCoordinateSystems() > 0)
{
for (int cc = 0; cc < rp.out_link().size(); ++cc)
{
auto target = rp.out_link().target(cc);
// let's get the bounding box for the target block.
vtkmdiy::ContinuousBounds bds(3);
this->Decomposer.fill_bounds(bds, target.gid);
auto extractedDS = this->Extract(*block, bds);
rp.enqueue(target, vtkm::filter::MakeSerializableDataSet(extractedDS, this->Filter));
}
// clear our dataset.
*block = vtkm::cont::DataSet();
}
}
else
{
vtkm::Id numValues = 0;
std::vector<vtkm::cont::DataSet> receives;
for (int cc = 0; cc < rp.in_link().size(); ++cc)
{
auto target = rp.in_link().target(cc);
if (rp.incoming(target.gid).size() > 0)
{
auto sds = vtkm::filter::MakeSerializableDataSet(this->Filter);
rp.dequeue(target.gid, sds);
receives.push_back(sds.DataSet);
numValues += receives.back().GetCoordinateSystem(0).GetNumberOfPoints();
}
}
*block = vtkm::cont::DataSet();
if (receives.size() == 1)
{
*block = receives[0];
}
else if (receives.size() > 1)
{
ConcatenateFields concatCoords(numValues);
for (const auto& ds : receives)
{
concatCoords.Append(ds.GetCoordinateSystem(0));
}
block->AddCoordinateSystem(vtkm::cont::CoordinateSystem(
concatCoords.GetResult().GetName(), concatCoords.GetResult().GetData()));
for (vtkm::IdComponent i = 0; i < receives[0].GetNumberOfFields(); ++i)
{
ConcatenateFields concatField(numValues);
for (const auto& ds : receives)
{
concatField.Append(ds.GetField(i));
}
block->AddField(concatField.GetResult());
}
}
}
}
};
} // namespace example::internal
class RedistributePoints : public vtkm::filter::Filter<RedistributePoints>
class RedistributePoints : public vtkm::filter::NewFilter
{
public:
VTKM_CONT
RedistributePoints() {}
VTKM_CONT RedistributePoints() {}
VTKM_CONT
~RedistributePoints() {}
VTKM_CONT ~RedistributePoints() {}
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::PartitionedDataSet PrepareForExecution(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
protected:
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& input) override;
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override;
};
template <typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::PartitionedDataSet RedistributePoints::PrepareForExecution(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
// let's first get the global bounds of the domain
vtkm::Bounds gbounds = vtkm::cont::BoundsGlobalCompute(input);
vtkm::cont::AssignerPartitionedDataSet assigner(input.GetNumberOfPartitions());
vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds> decomposer(
/*dim*/ 3, internal::convert(gbounds), assigner.nblocks());
vtkmdiy::Master master(
comm,
/*threads*/ 1,
/*limit*/ -1,
[]() -> void* { return new vtkm::cont::DataSet(); },
[](void* ptr) { delete static_cast<vtkm::cont::DataSet*>(ptr); });
decomposer.decompose(comm.rank(), assigner, master);
assert(static_cast<vtkm::Id>(master.size()) == input.GetNumberOfPartitions());
// let's populate local blocks
master.foreach ([&input](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink& proxy) {
auto lid = proxy.master()->lid(proxy.gid());
*ds = input.GetPartition(lid);
});
internal::Redistributor<RedistributePoints> redistributor(decomposer, *this);
vtkmdiy::all_to_all(master, assigner, redistributor, /*k=*/2);
vtkm::cont::PartitionedDataSet result;
master.foreach ([&result](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink&) {
result.AppendPartition(*ds);
});
return result;
}
} // namespace example
#endif //example_RedistributePoints_h

@ -0,0 +1,60 @@
//============================================================================
// 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/DataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/thirdparty/diy/diy.h>
#include "RedistributePoints.h"
#include <sstream>
using std::cout;
using std::endl;
int main(int argc, char* argv[])
{
// Process vtk-m general args
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
auto config = vtkm::cont::Initialize(argc, argv, opts);
vtkmdiy::mpi::environment env(argc, argv);
vtkmdiy::mpi::communicator comm;
vtkm::cont::EnvironmentTracker::SetCommunicator(comm);
if (argc != 3)
{
cout << "Usage: " << endl
<< "$ " << argv[0] << " [options] <input-vtk-file> <output-file-prefix>" << endl;
cout << config.Usage << endl;
return EXIT_FAILURE;
}
vtkm::cont::DataSet input;
if (comm.rank() == 0)
{
vtkm::io::VTKDataSetReader reader(argv[1]);
input = reader.ReadDataSet();
}
example::RedistributePoints redistributor;
auto output = redistributor.Execute(input);
std::ostringstream str;
str << argv[2] << "-" << comm.rank() << ".vtk";
vtkm::io::VTKDataSetWriter writer(str.str());
writer.WriteDataSet(output);
return EXIT_SUCCESS;
}

@ -16,12 +16,5 @@ find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_MPI)
add_executable(StreamlineMPI StreamlineMPI.cxx)
target_compile_definitions(StreamlineMPI PRIVATE "MPI_ENABLED")
target_link_libraries(StreamlineMPI PRIVATE vtkm_filter vtkm_io MPI::MPI_CXX)
vtkm_add_target_information(StreamlineMPI
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES StreamlineMPI.cxx)
target_link_libraries(StreamlineMPI PRIVATE vtkm_filter_flow vtkm_io MPI::MPI_CXX)
endif()
#if(TARGET vtkm::tbb)
# target_compile_definitions(streamline_mpi PRIVATE BUILDING_TBB_VERSION)
#endif()

@ -8,13 +8,14 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/Particle.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/Streamline.h>
#include <vtkm/filter/flow/ParticleAdvection.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/io/reader/VTKDataSetReader.h>
@ -23,12 +24,6 @@
#include <vtkm/thirdparty/diy/diy.h>
#include <vtkm/thirdparty/diy/mpi-cast.h>
#include <vtkm/filter/ParticleAdvection.h>
#include <vtkm/filter/particleadvection/BoundsMap.h>
#include <vtkm/filter/particleadvection/ParticleMessenger.h>
void LoadData(std::string& fname, std::vector<vtkm::cont::DataSet>& dataSets, int rank, int nRanks)
{
std::string buff;
@ -99,7 +94,7 @@ int main(int argc, char** argv)
std::vector<vtkm::cont::DataSet> dataSets;
LoadData(dataFile, dataSets, rank, size);
vtkm::filter::ParticleAdvection pa;
vtkm::filter::flow::ParticleAdvection pa;
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
seedArray = vtkm::cont::make_ArrayHandle({ vtkm::Particle(vtkm::Vec3f(.1f, .1f, .9f), 0),

@ -12,11 +12,14 @@
#include <string>
#include <vector>
#include <vtkm/Particle.h>
//#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/Timer.h>
//#include <vtkm/cont/Timer.h>
#include <vtkm/filter/Pathline.h>
#include <vtkm/filter/flow/Pathline.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
@ -91,7 +94,7 @@ int main(int argc, char** argv)
// Instantiate the filter by providing necessary parameters.
// Necessary parameters are :
vtkm::filter::Pathline pathlineFilter;
vtkm::filter::flow::Pathline pathlineFilter;
pathlineFilter.SetActiveField(fieldName);
// 1. The current and next time slice. The current time slice is passed
// through the parameter to the Execute method.

@ -18,9 +18,3 @@ target_link_libraries(Tetrahedralize PRIVATE vtkm_filter vtkm_io)
add_executable(Triangulate Triangulate.cxx)
target_link_libraries(Triangulate PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Tetrahedralize Triangulate
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
Tetrahedralize.cxx Triangulate.cxx)

@ -36,11 +36,16 @@ target_link_libraries(two_filters vtkm_filter vtkm_io)
add_executable(mag_grad mag_grad.cxx)
target_link_libraries(mag_grad vtkm_filter 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
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES mag_grad.cxx)
if (VTKm_ENABLE_RENDERING)
add_executable(rendering rendering.cxx)
target_link_libraries(rendering vtkm_filter vtkm_io vtkm_rendering)
endif()
endif ()
add_executable(error_handling error_handling.cxx)
target_link_libraries(error_handling vtkm_filter vtkm_io)
@ -50,46 +55,15 @@ target_link_libraries(logging vtkm_filter vtkm_io)
add_executable(point_to_cell point_to_cell.cxx)
target_link_libraries(point_to_cell vtkm_cont vtkm_filter 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)
set(tutorial_targets
io
contour
contour_two_fields
two_filters
mag_grad
error_handling
logging
point_to_cell
extract_edges
)
set(tutorial_sources
io.cxx
contour.cxx
contour_two_fields.cxx
two_filters.cxx
mag_grad.cxx
error_handling.cxx
logging.cxx
point_to_cell.cxx
extract_edges.cxx
)
if (VTKm_ENABLE_RENDERING)
list(APPEND tutorial_sources rendering.cxx)
list(APPEND tutorial_targets rendering)
endif()
vtkm_add_target_information(${tutorial_targets}
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
${tutorial_sources})
vtkm_add_target_information(extract_edges
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES extract_edges.cxx)
# Copy the data file to be adjacent to the binaries
file(GENERATE OUTPUT "$<TARGET_FILE_DIR:mag_grad>/data/kitchen.vtk" INPUT "${CMAKE_CURRENT_SOURCE_DIR}/data/kitchen.vtk")

@ -20,7 +20,9 @@
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/filter/MapFieldMergeAverage.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/filter/NewFilter.h>
#include <vtkm/filter/contour/Contour.h>
#include <vtkm/worklet/WorkletMapTopology.h>
@ -117,95 +119,23 @@ struct EdgeIndicesWorklet : vtkm::worklet::WorkletReduceByKey
namespace
{
class ExtractEdges : public vtkm::filter::FilterDataSet<ExtractEdges>
{
public:
template <typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy);
template <typename T, typename StorageType, typename Policy>
VTKM_CONT bool DoMapField(vtkm::cont::DataSet& result,
const vtkm::cont::ArrayHandle<T, StorageType>& input,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>& policy);
private:
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
vtkm::worklet::Keys<vtkm::Id2> CellToEdgeKeys;
};
template <typename Policy>
inline VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(
const vtkm::cont::DataSet& inData,
vtkm::filter::PolicyBase<Policy> policy)
{
auto inCellSet = vtkm::filter::ApplyPolicyCellSet(inData.GetCellSet(), policy, *this);
// First, count the edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
this->Invoke(CountEdgesWorklet{}, inCellSet, edgeCounts);
// Second, using these counts build a scatter that repeats a cell's visit
// for each edge in the cell.
vtkm::worklet::ScatterCounting scatter(edgeCounts);
this->OutputToInputCellMap = scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::worklet::ScatterCounting::VisitArrayType outputToInputEdgeMap =
scatter.GetVisitArray(inCellSet.GetNumberOfCells());
// Third, for each edge, extract a canonical id.
vtkm::cont::ArrayHandle<vtkm::Id2> canonicalIds;
this->Invoke(EdgeIdsWorklet{}, scatter, inCellSet, canonicalIds);
// Fourth, construct a Keys object to combine all like edge ids.
this->CellToEdgeKeys = vtkm::worklet::Keys<vtkm::Id2>(canonicalIds);
// Fifth, use a reduce-by-key to extract indices for each unique edge.
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
this->Invoke(EdgeIndicesWorklet{},
this->CellToEdgeKeys,
inCellSet,
this->OutputToInputCellMap,
outputToInputEdgeMap,
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
// Sixth, use the created connectivity array to build a cell set.
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
vtkm::cont::DataSet outData;
outData.SetCellSet(outCellSet);
for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems();
++coordSystemIndex)
{
outData.AddCoordinateSystem(inData.GetCoordinateSystem(coordSystemIndex));
}
return outData;
}
template <typename T, typename StorageType, typename Policy>
inline VTKM_CONT bool ExtractEdges::DoMapField(
VTKM_CONT bool DoMapField(
vtkm::cont::DataSet& result,
const vtkm::cont::ArrayHandle<T, StorageType>& inputArray,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<Policy>&)
const vtkm::cont::Field& inputField,
const vtkm::worklet::ScatterCounting::OutputToInputMapType& OutputToInputCellMap,
const vtkm::worklet::Keys<vtkm::Id2>& CellToEdgeKeys)
{
vtkm::cont::Field outputField;
if (fieldMeta.IsPointField())
if (inputField.IsPointField())
{
outputField = fieldMeta.AsField(inputArray); // pass through
outputField = inputField; // pass through
}
else if (fieldMeta.IsCellField())
else if (inputField.IsCellField())
{
auto outputCellArray = vtkm::worklet::AverageByKey::Run(
this->CellToEdgeKeys,
vtkm::cont::make_ArrayHandlePermutation(this->OutputToInputCellMap, inputArray));
outputField = fieldMeta.AsField(outputCellArray);
vtkm::cont::Field permuted;
vtkm::filter::MapFieldPermutation(inputField, OutputToInputCellMap, permuted);
vtkm::filter::MapFieldMergeAverage(permuted, CellToEdgeKeys, outputField);
}
else
{
@ -217,6 +147,55 @@ inline VTKM_CONT bool ExtractEdges::DoMapField(
return true;
}
class ExtractEdges : public vtkm::filter::NewFilter
{
public:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inData) override;
};
VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(const vtkm::cont::DataSet& inData)
{
auto inCellSet = inData.GetCellSet();
// First, count the edges in each cell.
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
this->Invoke(CountEdgesWorklet{}, inCellSet, edgeCounts);
// Second, using these counts build a scatter that repeats a cell's visit
// for each edge in the cell.
vtkm::worklet::ScatterCounting scatter(edgeCounts);
vtkm::worklet::ScatterCounting::OutputToInputMapType OutputToInputCellMap;
OutputToInputCellMap = scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
vtkm::worklet::ScatterCounting::VisitArrayType outputToInputEdgeMap =
scatter.GetVisitArray(inCellSet.GetNumberOfCells());
// Third, for each edge, extract a canonical id.
vtkm::cont::ArrayHandle<vtkm::Id2> canonicalIds;
this->Invoke(EdgeIdsWorklet{}, scatter, inCellSet, canonicalIds);
// Fourth, construct a Keys object to combine all like edge ids.
vtkm::worklet::Keys<vtkm::Id2> CellToEdgeKeys;
CellToEdgeKeys = vtkm::worklet::Keys<vtkm::Id2>(canonicalIds);
// Fifth, use a reduce-by-key to extract indices for each unique edge.
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
this->Invoke(EdgeIndicesWorklet{},
CellToEdgeKeys,
inCellSet,
OutputToInputCellMap,
outputToInputEdgeMap,
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
// Sixth, use the created connectivity array to build a cell set.
vtkm::cont::CellSetSingleType<> outCellSet;
outCellSet.Fill(inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
auto mapper = [&](auto& outDataSet, const auto& f) {
DoMapField(outDataSet, f, OutputToInputCellMap, CellToEdgeKeys);
};
return this->CreateResult(inData, outCellSet, inData.GetCoordinateSystems(), mapper);
}
}
int main(int argc, char** argv)

@ -28,29 +28,30 @@ struct ComputeMagnitude : vtkm::worklet::WorkletMapField
}
};
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/NewFilterField.h>
class FieldMagnitude : public vtkm::filter::FilterField<FieldMagnitude>
class FieldMagnitude : public vtkm::filter::NewFilterField
{
public:
using SupportedTypes = vtkm::List<vtkm::Vec3f>;
template <typename ArrayHandleType, typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet,
const ArrayHandleType& inField,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<Policy>)
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet) override
{
const auto& inField = this->GetFieldFromDataSet(inDataSet);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outField;
this->Invoke(ComputeMagnitude{}, inField, outField);
auto resolveType = [&](const auto& concrete) {
this->Invoke(ComputeMagnitude{}, concrete, outField);
};
this->CastAndCallVecField<3>(inField, resolveType);
std::string outFieldName = this->GetOutputFieldName();
if (outFieldName == "")
{
outFieldName = fieldMetadata.GetName() + "_magnitude";
outFieldName = inField.GetName() + "_magnitude";
}
return vtkm::filter::CreateResult(inDataSet, outField, outFieldName, fieldMetadata);
return this->CreateResultFieldCell(inDataSet, outFieldName, outField);
}
};

@ -46,46 +46,39 @@ struct ConvertPointFieldToCells : vtkm::worklet::WorkletVisitCellsWithPoints
} // namespace worklet
} // namespace vtkm
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/NewFilterField.h>
namespace vtkm
{
namespace filter
{
struct ConvertPointFieldToCells : vtkm::filter::FilterField<ConvertPointFieldToCells>
struct ConvertPointFieldToCells : vtkm::filter::NewFilterField
{
template <typename ArrayHandleType, typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet,
const ArrayHandleType& inField,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<Policy>);
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inDataSet) override;
};
template <typename ArrayHandleType, typename Policy>
VTKM_CONT cont::DataSet ConvertPointFieldToCells::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const ArrayHandleType& inField,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<Policy> policy)
VTKM_CONT cont::DataSet ConvertPointFieldToCells::DoExecute(const vtkm::cont::DataSet& inDataSet)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
const auto& inField = this->GetFieldFromDataSet(inDataSet);
using ValueType = typename ArrayHandleType::ValueType;
vtkm::cont::UnknownArrayHandle outArray;
auto resolveType = [&](const auto& concrete) {
using ValueType = typename std::decay_t<decltype(concrete)>::ValueType;
vtkm::cont::ArrayHandle<ValueType> outField;
this->Invoke(vtkm::worklet::ConvertPointFieldToCells{},
vtkm::filter::ApplyPolicyCellSet(inDataSet.GetCellSet(), policy, *this),
inField,
outField);
vtkm::cont::ArrayHandle<ValueType> outField;
this->Invoke(
vtkm::worklet::ConvertPointFieldToCells{}, inDataSet.GetCellSet(), concrete, outField);
outArray = outField;
};
this->CastAndCallScalarField(inField, resolveType);
std::string outFieldName = this->GetOutputFieldName();
if (outFieldName == "")
{
outFieldName = fieldMetadata.GetName();
outFieldName = inField.GetName();
}
return vtkm::filter::CreateResultFieldCell(inDataSet, outField, outFieldName);
return this->CreateResultFieldCell(inDataSet, outFieldName, outArray);
}
} // namespace filter

@ -12,7 +12,6 @@
#include <vtkm/cont/Initialize.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/rendering/Actor.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/MapperRayTracer.h>

@ -1 +1 @@
1.8.0
1.8.9999

@ -14,6 +14,8 @@
#include <vtkm/internal/Meta.h>
#include <functional>
namespace vtkm
{

@ -55,6 +55,16 @@ public:
VTKM_EXEC_CONT void ClearInGhostCell() { this->reset(this->IN_GHOST_CELL_BIT); }
VTKM_EXEC_CONT bool CheckInGhostCell() const { return this->test(this->IN_GHOST_CELL_BIT); }
VTKM_EXEC_CONT void SetZeroVelocity() { this->set(this->ZERO_VELOCITY); }
VTKM_EXEC_CONT void ClearZeroVelocity() { this->reset(this->ZERO_VELOCITY); }
VTKM_EXEC_CONT bool CheckZeroVelocity() const { return this->test(this->ZERO_VELOCITY); }
VTKM_EXEC_CONT bool CanContinue() const
{
return this->CheckOk() && !this->CheckTerminate() && !this->CheckSpatialBounds() &&
!this->CheckTemporalBounds() && !this->CheckInGhostCell() && !this->CheckZeroVelocity();
}
private:
static constexpr vtkm::Id SUCCESS_BIT = 0;
static constexpr vtkm::Id TERMINATE_BIT = 1;
@ -62,6 +72,7 @@ private:
static constexpr vtkm::Id TEMPORAL_BOUNDS_BIT = 3;
static constexpr vtkm::Id TOOK_ANY_STEPS_BIT = 4;
static constexpr vtkm::Id IN_GHOST_CELL_BIT = 5;
static constexpr vtkm::Id ZERO_VELOCITY = 6;
};
inline VTKM_CONT std::ostream& operator<<(std::ostream& s, const vtkm::ParticleStatus& status)
@ -71,6 +82,7 @@ inline VTKM_CONT std::ostream& operator<<(std::ostream& s, const vtkm::ParticleS
s << " spat= " << status.CheckSpatialBounds();
s << " temp= " << status.CheckTemporalBounds();
s << " ghst= " << status.CheckInGhostCell();
s << " zvel= " << status.CheckZeroVelocity();
s << "]";
return s;
}
@ -142,6 +154,17 @@ public:
vtkm::Id NumSteps = 0;
vtkm::ParticleStatus Status;
vtkm::FloatDefault Time = 0;
static size_t Sizeof()
{
constexpr std::size_t sz = sizeof(vtkm::Vec3f) // Pos
+ sizeof(vtkm::Id) // ID
+ sizeof(vtkm::Id) // NumSteps
+ sizeof(vtkm::UInt8) // Status
+ sizeof(vtkm::FloatDefault); // Time
return sz;
}
};
class ChargedParticle
@ -153,9 +176,9 @@ public:
VTKM_EXEC_CONT
ChargedParticle(const vtkm::Vec3f& position,
const vtkm::Id& id,
const vtkm::FloatDefault& mass,
const vtkm::FloatDefault& charge,
const vtkm::FloatDefault& weighting,
const vtkm::Float64& mass,
const vtkm::Float64& charge,
const vtkm::Float64& weighting,
const vtkm::Vec3f& momentum,
const vtkm::Id& numSteps = 0,
const vtkm::ParticleStatus& status = vtkm::ParticleStatus(),
@ -173,16 +196,16 @@ public:
}
VTKM_EXEC_CONT
vtkm::FloatDefault Gamma(vtkm::Vec3f momentum, bool reciprocal = false) const
vtkm::Float64 Gamma(vtkm::Vec3f momentum, bool reciprocal = false) const
{
constexpr vtkm::FloatDefault c2 = SPEED_OF_LIGHT * SPEED_OF_LIGHT;
const auto fMom2 = vtkm::MagnitudeSquared(momentum);
const auto m2 = this->Mass * this->Mass;
const auto m2_c2_reci = 1.0 / (m2 * c2);
const vtkm::Float64 fMom2 = vtkm::MagnitudeSquared(momentum);
const vtkm::Float64 m2 = this->Mass * this->Mass;
const vtkm::Float64 m2_c2_reci = 1.0 / (m2 * c2);
if (reciprocal)
return static_cast<vtkm::FloatDefault>(vtkm::RSqrt(1.0 + fMom2 * m2_c2_reci));
return vtkm::RSqrt(1.0 + fMom2 * m2_c2_reci);
else
return static_cast<vtkm::FloatDefault>(vtkm::Sqrt(1.0 + fMom2 * m2_c2_reci));
return vtkm::Sqrt(1.0 + fMom2 * m2_c2_reci);
}
VTKM_EXEC_CONT
@ -197,11 +220,11 @@ public:
vtkm::Vec3f eField = vectors[0];
vtkm::Vec3f bField = vectors[1];
const vtkm::FloatDefault QoM = this->Charge / this->Mass;
const vtkm::Float64 QoM = this->Charge / this->Mass;
const vtkm::Vec3f mom_minus = this->Momentum + (0.5 * this->Charge * eField * length);
// Get reciprocal of Gamma
vtkm::Vec3f gamma_reci = this->Gamma(mom_minus, true);
vtkm::Vec3f gamma_reci = static_cast<vtkm::FloatDefault>(this->Gamma(mom_minus, true));
const vtkm::Vec3f t = 0.5 * QoM * length * bField * gamma_reci;
const vtkm::Vec3f s = 2.0f * t * (1.0 / (1.0 + vtkm::Magnitude(t)));
const vtkm::Vec3f mom_prime = mom_minus + vtkm::Cross(mom_minus, t);
@ -228,6 +251,14 @@ public:
return this->Pos + translation;
}
inline VTKM_CONT friend std::ostream& operator<<(std::ostream& out,
const vtkm::ChargedParticle& p)
{
out << "v(" << p.Time << ") = " << p.Pos << ", ID: " << p.ID << ", NumSteps: " << p.NumSteps
<< ", Status: " << p.Status;
return out;
}
vtkm::Vec3f Pos;
vtkm::Id ID = -1;
vtkm::Id NumSteps = 0;
@ -235,14 +266,30 @@ public:
vtkm::FloatDefault Time = 0;
private:
vtkm::FloatDefault Mass;
vtkm::FloatDefault Charge;
vtkm::FloatDefault Weighting;
vtkm::Float64 Mass;
vtkm::Float64 Charge;
vtkm::Float64 Weighting;
vtkm::Vec3f Momentum;
constexpr static vtkm::FloatDefault SPEED_OF_LIGHT =
static_cast<vtkm::FloatDefault>(2.99792458e8);
friend struct mangled_diy_namespace::Serialization<vtkm::ChargedParticle>;
public:
static size_t Sizeof()
{
constexpr std::size_t sz = sizeof(vtkm::Vec3f) // Pos
+ sizeof(vtkm::Id) // ID
+ sizeof(vtkm::Id) // NumSteps
+ sizeof(vtkm::UInt8) // Status
+ sizeof(vtkm::FloatDefault) // Time
+ sizeof(vtkm::Float64) //Mass
+ sizeof(vtkm::Float64) //Charge
+ sizeof(vtkm::Float64) //Weighting
+ sizeof(vtkm::Vec3f); //Momentum
return sz;
}
};
} //namespace vtkm

@ -498,6 +498,7 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::VecCConst<T>>
namespace internal
{
/// Used for overriding VecTraits for basic scalar types.
///
template <typename ScalarType>
@ -539,6 +540,44 @@ struct VTKM_NEVER_EXPORT VecTraitsBasic
dest[0] = src;
}
};
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>
{
};
} // namespace internal
/// \brief VecTraits for Pair types
@ -554,7 +593,7 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Pair<T, U>>
{
};
} // anonymous namespace
} // namespace vtkm
#define VTKM_BASIC_TYPE_VECTOR(type) \
namespace vtkm \

@ -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::VecTraits<T>::BaseComponentType>
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<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::VecTraits<T>::BaseComponentType;
using BaseComponentType = typename vtkm::internal::SafeVecTraits<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::VecTraits<T>::BaseComponentType> operator()(
const vtkm::cont::ArrayHandle<T, S>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
vtkm::cont::ArrayHandleStride<typename vtkm::internal::SafeVecTraits<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,13 +93,15 @@ template <>
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagStride>
{
template <typename T>
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
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
{
return this->DoExtract(
src, componentIndex, allowCopy, typename vtkm::VecTraits<T>::HasMultipleComponents{});
return this->DoExtract(src,
componentIndex,
allowCopy,
typename vtkm::internal::SafeVecTraits<T>::HasMultipleComponents{});
}
private:
@ -110,7 +112,7 @@ private:
vtkm::VecTraitsTagSingleComponent) const
{
VTKM_ASSERT(componentIndex == 0);
using VTraits = vtkm::VecTraits<T>;
using VTraits = vtkm::internal::SafeVecTraits<T>;
using TBase = typename VTraits::BaseComponentType;
VTKM_STATIC_ASSERT(VTraits::NUM_COMPONENTS == 1);
@ -133,7 +135,7 @@ private:
vtkm::CopyFlag allowCopy,
vtkm::VecTraitsTagMultipleComponents) const
{
using VTraits = vtkm::VecTraits<VecType>;
using VTraits = vtkm::internal::SafeVecTraits<VecType>;
using T = typename VTraits::ComponentType;
constexpr vtkm::IdComponent N = VTraits::NUM_COMPONENTS;
@ -252,10 +254,10 @@ using ArrayExtractComponentIsInefficient = typename std::is_base_of<
/// `vtkm::cont::internal::ArrayExtractComponentImpl`.
///
template <typename T, typename S>
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)
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)
{
return internal::ArrayExtractComponentImpl<S>{}(src, componentIndex, allowCopy);
}

@ -314,7 +314,7 @@ public:
/// Constructs an empty ArrayHandle.
///
VTKM_CONT ArrayHandle()
: Buffers(static_cast<std::size_t>(StorageType::GetNumberOfBuffers()))
: Buffers(StorageType::CreateBuffers())
{
}
@ -349,17 +349,10 @@ public:
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
: Buffers(buffers)
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
: Buffers(std::move(buffers))
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers)
: Buffers(buffers, buffers + StorageType::GetNumberOfBuffers())
{
}
///@}
@ -420,9 +413,10 @@ public:
return true; // different valuetype and/or storage
}
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers()
VTKM_DEPRECATED(1.9, "Use the size of the std::vector returned from GetBuffers.")
VTKM_CONT constexpr vtkm::IdComponent GetNumberOfBuffers()
{
return StorageType::GetNumberOfBuffers();
return static_cast<vtkm::IdComponent>(this->GetBuffers().size());
}
/// Get the storage.
@ -776,9 +770,15 @@ public:
}
}
/// Returns the internal `Buffer` structures that hold the data.
/// \brief Returns the internal `Buffer` structures that hold the data.
///
VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const { return this->Buffers.data(); }
/// Note that great care should be taken when modifying buffers outside of the ArrayHandle.
///
VTKM_CONT const std::vector<vtkm::cont::internal::Buffer>& GetBuffers() const
{
return this->Buffers;
}
VTKM_CONT std::vector<vtkm::cont::internal::Buffer>& GetBuffers() { return this->Buffers; }
private:
mutable std::vector<vtkm::cont::internal::Buffer> Buffers;
@ -789,11 +789,13 @@ protected:
this->Buffers[static_cast<std::size_t>(index)] = buffer;
}
// BufferContainer must be an iteratable container of Buffer objects.
template <typename BufferContainer>
VTKM_CONT void SetBuffers(const BufferContainer& buffers)
VTKM_CONT void SetBuffers(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
std::copy(buffers.begin(), buffers.end(), this->Iterators->Buffers.begin());
this->Buffers = buffers;
}
VTKM_CONT void SetBuffers(std::vector<vtkm::cont::internal::Buffer>&& buffers)
{
this->Buffers = std::move(buffers);
}
};
@ -831,9 +833,9 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value(
std::ostream& out,
vtkm::VecTraitsTagMultipleComponents)
{
using Traits = vtkm::VecTraits<T>;
using Traits = vtkm::internal::SafeVecTraits<T>;
using ComponentType = typename Traits::ComponentType;
using IsVecOfVec = typename vtkm::VecTraits<ComponentType>::HasMultipleComponents;
using IsVecOfVec = typename vtkm::internal::SafeVecTraits<ComponentType>::HasMultipleComponents;
vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value);
out << "(";
printSummary_ArrayHandle_Value(Traits::GetComponent(value, 0), out, IsVecOfVec());
@ -853,10 +855,10 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value(
{
out << "{";
printSummary_ArrayHandle_Value(
value.first, out, typename vtkm::VecTraits<T1>::HasMultipleComponents());
value.first, out, typename vtkm::internal::SafeVecTraits<T1>::HasMultipleComponents());
out << ",";
printSummary_ArrayHandle_Value(
value.second, out, typename vtkm::VecTraits<T2>::HasMultipleComponents());
value.second, out, typename vtkm::internal::SafeVecTraits<T2>::HasMultipleComponents());
out << "}";
}
@ -872,7 +874,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::VecTraits<T>::HasMultipleComponents;
using IsVec = typename vtkm::internal::SafeVecTraits<T>::HasMultipleComponents;
vtkm::Id sz = array.GetNumberOfValues();
@ -915,6 +917,25 @@ namespace internal
namespace detail
{
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>&);
template <typename T, typename S, typename... Args>
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>& buffers,
const vtkm::cont::ArrayHandle<T, S>& array,
const Args&... args);
template <typename... Args>
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>& buffers,
const vtkm::cont::internal::Buffer& buffer,
const Args&... args);
template <typename... Args>
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>& buffers,
const std::vector<vtkm::cont::internal::Buffer>& addbuffs,
const Args&... args);
template <typename Arg0, typename... Args>
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>& buffers,
const Arg0& arg0,
const Args&... args);
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>&)
{
// Nothing left to add.
@ -925,9 +946,7 @@ VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer
const vtkm::cont::ArrayHandle<T, S>& array,
const Args&... args)
{
vtkm::cont::internal::Buffer* arrayBuffers = array.GetBuffers();
buffers.insert(buffers.end(), arrayBuffers, arrayBuffers + array.GetNumberOfBuffers());
CreateBuffersImpl(buffers, args...);
CreateBuffersImpl(buffers, array.GetBuffers(), args...);
}
template <typename... Args>
@ -948,11 +967,6 @@ VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer
CreateBuffersImpl(buffers, args...);
}
template <typename Arg0, typename... Args>
VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer>& buffers,
const Arg0& arg0,
const Args&... args);
template <typename T, typename S, typename... Args>
VTKM_CONT inline void CreateBuffersResolveArrays(std::vector<vtkm::cont::internal::Buffer>& buffers,
std::true_type,
@ -1001,7 +1015,7 @@ VTKM_CONT inline void CreateBuffersImpl(std::vector<vtkm::cont::internal::Buffer
/// - `ArrayHandle`: The buffers from the `ArrayHandle` are added to the list.
/// - `Buffer`: A copy of the buffer is added to the list.
/// - `std::vector<Buffer>`: A copy of all buffers in this vector are added to the list.
/// - Anything else: A buffer with the given object attached as metadata is
/// - Anything else: A buffer with the given object attached as metadata is added to the list.
///
template <typename... Args>
VTKM_CONT inline std::vector<vtkm::cont::internal::Buffer> CreateBuffers(const Args&... args)

@ -35,10 +35,13 @@ public:
using ReadPortalType = vtkm::internal::ArrayPortalBasicRead<T>;
using WritePortalType = vtkm::internal::ArrayPortalBasicWrite<T>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
{
return std::vector<vtkm::cont::internal::Buffer>(1);
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
@ -46,36 +49,43 @@ public:
vtkm::internal::NumberOfValuesToNumberOfBytes<T>(numValues), preserve, token);
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return static_cast<vtkm::Id>(buffers->GetNumberOfBytes() /
VTKM_ASSERT(buffers.size() == 1);
return static_cast<vtkm::Id>(buffers[0].GetNumberOfBytes() /
static_cast<vtkm::BufferSizeType>(sizeof(T)));
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
constexpr vtkm::BufferSizeType fillValueSize =
static_cast<vtkm::BufferSizeType>(sizeof(fillValue));
buffers[0].Fill(
&fillValue, fillValueSize, startIndex * fillValueSize, endIndex * fillValueSize, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
return ReadPortalType(reinterpret_cast<const T*>(buffers[0].ReadPointerDevice(device, token)),
GetNumberOfValues(buffers));
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
return WritePortalType(reinterpret_cast<T*>(buffers[0].WritePointerDevice(device, token)),
GetNumberOfValues(buffers));
}
@ -345,7 +355,8 @@ struct Serialization<vtkm::cont::ArrayHandleBasic<T>>
vtkm::cont::internal::Buffer buffer;
vtkmdiy::load(bb, buffer);
obj = vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>(&buffer);
obj = vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>(
vtkm::cont::internal::CreateBuffers(buffer));
}
};

@ -82,10 +82,13 @@ public:
using ReadPortalType = vtkm::cont::internal::ArrayPortalBitField<BitPortalConstType>;
using WritePortalType = vtkm::cont::internal::ArrayPortalBitField<BitPortalType>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
{
return std::vector<vtkm::cont::internal::Buffer>(1);
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numberOfBits,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
@ -102,20 +105,23 @@ public:
buffers[0].GetMetaData<vtkm::cont::internal::BitFieldMetaData>().NumberOfBits = numberOfBits;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
VTKM_ASSERT(buffers.size() == 1);
vtkm::Id numberOfBits =
buffers[0].GetMetaData<vtkm::cont::internal::BitFieldMetaData>().NumberOfBits;
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
return numberOfBits;
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
bool fillValue,
vtkm::Id startBit,
vtkm::Id endBit,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
constexpr vtkm::BufferSizeType wordTypeSize =
static_cast<vtkm::BufferSizeType>(sizeof(WordType));
constexpr vtkm::BufferSizeType wordNumBits = wordTypeSize * CHAR_BIT;
@ -141,10 +147,12 @@ public:
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
vtkm::Id numberOfBits = GetNumberOfValues(buffers);
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
@ -152,10 +160,12 @@ public:
BitPortalConstType(buffers[0].ReadPointerDevice(device, token), numberOfBits));
}
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
VTKM_ASSERT(buffers.size() == 1);
vtkm::Id numberOfBits = GetNumberOfValues(buffers);
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);

@ -17,6 +17,8 @@
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/Token.h>
#include <array>
namespace vtkm
{
namespace internal
@ -199,26 +201,27 @@ struct ArrayHandleCartesianProductTraits
template <typename T, typename ST1, typename ST2, typename ST3>
class Storage<vtkm::Vec<T, 3>, vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>
{
struct Info
{
std::array<std::size_t, 4> BufferOffset;
};
using Storage1 = vtkm::cont::internal::Storage<T, ST1>;
using Storage2 = vtkm::cont::internal::Storage<T, ST2>;
using Storage3 = vtkm::cont::internal::Storage<T, ST3>;
template <typename Buffs>
VTKM_CONT constexpr static Buffs* Buffers1(Buffs* buffers)
{
return buffers;
}
using Array1 = vtkm::cont::ArrayHandle<T, ST1>;
using Array2 = vtkm::cont::ArrayHandle<T, ST2>;
using Array3 = vtkm::cont::ArrayHandle<T, ST3>;
template <typename Buffs>
VTKM_CONT constexpr static Buffs* Buffers2(Buffs* buffers)
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> GetBuffers(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
std::size_t subArray)
{
return buffers + Storage1::GetNumberOfBuffers();
}
template <typename Buffs>
VTKM_CONT constexpr static Buffs* Buffers3(Buffs* buffers)
{
return buffers + Storage1::GetNumberOfBuffers() + Storage2::GetNumberOfBuffers();
Info info = buffers[0].GetMetaData<Info>();
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() +
info.BufferOffset[subArray - 1],
buffers.begin() + info.BufferOffset[subArray]);
}
public:
@ -235,20 +238,15 @@ public:
typename Storage2::WritePortalType,
typename Storage3::WritePortalType>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers()
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return Storage1::GetNumberOfBuffers() + Storage2::GetNumberOfBuffers() +
Storage3::GetNumberOfBuffers();
return (Storage1::GetNumberOfValues(GetBuffers(buffers, 1)) *
Storage2::GetNumberOfValues(GetBuffers(buffers, 2)) *
Storage3::GetNumberOfValues(GetBuffers(buffers, 3)));
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
return (Storage1::GetNumberOfValues(Buffers1(buffers)) *
Storage2::GetNumberOfValues(Buffers2(buffers)) *
Storage3::GetNumberOfValues(Buffers3(buffers)));
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
const vtkm::Vec<T, 3>& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
@ -259,46 +257,63 @@ public:
throw vtkm::cont::ErrorBadValue(
"Fill for ArrayHandleCartesianProduct can only be used to fill entire array.");
}
Storage1::Fill(
Buffers1(buffers), fillValue[0], 0, Storage1::GetNumberOfValues(Buffers1(buffers)), token);
Storage2::Fill(
Buffers2(buffers), fillValue[1], 0, Storage2::GetNumberOfValues(Buffers2(buffers)), token);
Storage3::Fill(
Buffers3(buffers), fillValue[2], 0, Storage3::GetNumberOfValues(Buffers3(buffers)), token);
auto subBuffers = GetBuffers(buffers, 1);
Storage1::Fill(subBuffers, fillValue[0], 0, Storage1::GetNumberOfValues(subBuffers), token);
subBuffers = GetBuffers(buffers, 2);
Storage2::Fill(subBuffers, fillValue[1], 0, Storage2::GetNumberOfValues(subBuffers), token);
subBuffers = GetBuffers(buffers, 3);
Storage3::Fill(subBuffers, fillValue[2], 0, Storage3::GetNumberOfValues(subBuffers), token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(Storage1::CreateReadPortal(Buffers1(buffers), device, token),
Storage2::CreateReadPortal(Buffers2(buffers), device, token),
Storage3::CreateReadPortal(Buffers3(buffers), device, token));
return ReadPortalType(Storage1::CreateReadPortal(GetBuffers(buffers, 1), device, token),
Storage2::CreateReadPortal(GetBuffers(buffers, 2), device, token),
Storage3::CreateReadPortal(GetBuffers(buffers, 3), device, token));
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(Storage1::CreateWritePortal(Buffers1(buffers), device, token),
Storage2::CreateWritePortal(Buffers2(buffers), device, token),
Storage3::CreateWritePortal(Buffers3(buffers), device, token));
return WritePortalType(Storage1::CreateWritePortal(GetBuffers(buffers, 1), device, token),
Storage2::CreateWritePortal(GetBuffers(buffers, 2), device, token),
Storage3::CreateWritePortal(GetBuffers(buffers, 3), device, token));
}
VTKM_CONT static vtkm::cont::ArrayHandle<T, ST1> GetArrayHandle1(
const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static Array1 GetArrayHandle1(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return vtkm::cont::ArrayHandle<T, ST1>(Buffers1(buffers));
return Array1(GetBuffers(buffers, 1));
}
VTKM_CONT static vtkm::cont::ArrayHandle<T, ST2> GetArrayHandle2(
const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static Array2 GetArrayHandle2(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return vtkm::cont::ArrayHandle<T, ST2>(Buffers2(buffers));
return Array2(GetBuffers(buffers, 2));
}
VTKM_CONT static vtkm::cont::ArrayHandle<T, ST3> GetArrayHandle3(
const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static Array3 GetArrayHandle3(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return vtkm::cont::ArrayHandle<T, ST3>(Buffers3(buffers));
return Array3(GetBuffers(buffers, 3));
}
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
const Array1& array1 = Array1{},
const Array2& array2 = Array2{},
const Array3& array3 = Array3{})
{
const std::vector<vtkm::cont::internal::Buffer>& buffers1 = array1.GetBuffers();
const std::vector<vtkm::cont::internal::Buffer>& buffers2 = array2.GetBuffers();
const std::vector<vtkm::cont::internal::Buffer>& buffers3 = array3.GetBuffers();
Info info;
info.BufferOffset[0] = 1;
info.BufferOffset[1] = info.BufferOffset[0] + buffers1.size();
info.BufferOffset[2] = info.BufferOffset[1] + buffers2.size();
info.BufferOffset[3] = info.BufferOffset[2] + buffers3.size();
return vtkm::cont::internal::CreateBuffers(info, buffers1, buffers2, buffers3);
}
};
} // namespace internal
@ -335,7 +350,7 @@ public:
ArrayHandleCartesianProduct(const FirstHandleType& firstArray,
const SecondHandleType& secondArray,
const ThirdHandleType& thirdArray)
: Superclass(vtkm::cont::internal::CreateBuffers(firstArray, secondArray, thirdArray))
: Superclass(StorageType::CreateBuffers(firstArray, secondArray, thirdArray))
{
}

@ -20,6 +20,7 @@
#include <vtkmstd/integer_sequence.h>
#include <numeric>
#include <type_traits>
namespace vtkm
@ -169,31 +170,6 @@ struct VerifyArrayHandle
"must be a list of ArrayHandle types.");
};
template <std::size_t I>
struct BufferIndexImpl
{
template <typename... Ts>
static constexpr vtkm::IdComponent Value(vtkm::IdComponent n, Ts... remaining)
{
return n + BufferIndexImpl<I - 1>::Value(remaining...);
}
};
template <>
struct BufferIndexImpl<0>
{
template <typename... Ts>
static constexpr vtkm::IdComponent Value(Ts...)
{
return 0;
}
};
template <std::size_t I, typename... StorageTypes>
constexpr vtkm::IdComponent BufferIndex()
{
return BufferIndexImpl<I>::Value(StorageTypes::GetNumberOfBuffers()...);
}
} // end namespace compvec
} // namespace internal
@ -226,21 +202,31 @@ class Storage<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags)
{
using ValueType = vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags))>;
struct Info
{
std::array<std::size_t, sizeof...(StorageTags) + 1> BufferOffset;
};
template <typename S>
using StorageFor = vtkm::cont::internal::Storage<T, S>;
using StorageTuple = vtkm::Tuple<StorageFor<StorageTags>...>;
template <std::size_t I>
VTKM_CONT static constexpr vtkm::IdComponent BufferIndex()
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> GetBuffers(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
std::size_t subArray)
{
return compvec::BufferIndex<I, StorageFor<StorageTags>...>();
Info info = buffers[0].GetMetaData<Info>();
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + info.BufferOffset[subArray],
buffers.begin() +
info.BufferOffset[subArray + 1]);
}
template <std::size_t I, typename Buff>
VTKM_CONT static Buff* Buffers(Buff* buffers)
template <std::size_t I>
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> Buffers(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers + BufferIndex<I>();
return GetBuffers(buffers, I);
}
using IndexList = vtkmstd::make_index_sequence<sizeof...(StorageTags)>;
@ -255,19 +241,21 @@ private:
template <std::size_t... Is>
static void ResizeBuffersImpl(vtkmstd::index_sequence<Is...>,
vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
std::vector<std::vector<vtkm::cont::internal::Buffer>> bufferPartitions = { Buffers<Is>(
buffers)... };
auto init_list = { (vtkm::tuple_element_t<Is, StorageTuple>::ResizeBuffers(
numValues, Buffers<Is>(buffers), preserve, token),
numValues, bufferPartitions[Is], preserve, token),
false)... };
(void)init_list;
}
template <std::size_t... Is>
static void FillImpl(vtkmstd::index_sequence<Is...>,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
@ -284,45 +272,43 @@ private:
}
template <std::size_t... Is>
static ReadPortalType CreateReadPortalImpl(vtkmstd::index_sequence<Is...>,
const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
static ReadPortalType CreateReadPortalImpl(
vtkmstd::index_sequence<Is...>,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(vtkm::tuple_element_t<Is, StorageTuple>::CreateReadPortal(
Buffers<Is>(buffers), device, token)...);
}
template <std::size_t... Is>
static WritePortalType CreateWritePortalImpl(vtkmstd::index_sequence<Is...>,
vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
static WritePortalType CreateWritePortalImpl(
vtkmstd::index_sequence<Is...>,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(vtkm::tuple_element_t<Is, StorageTuple>::CreateWritePortal(
Buffers<Is>(buffers), device, token)...);
}
public:
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers()
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return BufferIndex<sizeof...(StorageTags)>();
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
return vtkm::TupleElement<0, StorageTuple>::GetNumberOfValues(buffers);
return vtkm::TupleElement<0, StorageTuple>::GetNumberOfValues(Buffers<0>(buffers));
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
ResizeBuffersImpl(IndexList{}, numValues, buffers, preserve, token);
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
@ -331,65 +317,51 @@ public:
FillImpl(IndexList{}, buffers, fillValue, startIndex, endIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return CreateReadPortalImpl(IndexList{}, buffers, device, token);
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return CreateWritePortalImpl(IndexList{}, buffers, device, token);
}
private:
template <typename ArrayType>
VTKM_CONT static bool CopyBuffers(const ArrayType& array,
vtkm::cont::internal::Buffer* destBuffers)
{
vtkm::IdComponent numBuffers = array.GetNumberOfBuffers();
const vtkm::cont::internal::Buffer* srcBuffers = array.GetBuffers();
for (vtkm::IdComponent buffIndex = 0; buffIndex < numBuffers; ++buffIndex)
{
destBuffers[buffIndex] = srcBuffers[buffIndex];
}
return false; // Return value does not matter. Hopefully just thrown away by compiler.
}
template <std::size_t... Is, typename... ArrayTs>
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffersImpl(
vtkmstd::index_sequence<Is...>,
const ArrayTs... arrays)
{
std::vector<vtkm::cont::internal::Buffer> buffers(
static_cast<std::size_t>(GetNumberOfBuffers()));
auto init_list = { CopyBuffers(arrays, Buffers<Is>(&buffers.front()))... };
(void)init_list;
return buffers;
}
public:
template <typename... ArrayTs>
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(const ArrayTs... arrays)
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
const vtkm::cont::ArrayHandle<T, StorageTags>&... arrays)
{
return CreateBuffersImpl(IndexList{}, arrays...);
auto numBuffers = { std::size_t{ 1 }, arrays.GetBuffers().size()... };
Info info;
std::partial_sum(numBuffers.begin(), numBuffers.end(), info.BufferOffset.begin());
return vtkm::cont::internal::CreateBuffers(info, arrays...);
}
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
{
return CreateBuffers(vtkm::cont::ArrayHandle<T, StorageTags>{}...);
}
private:
using ArrayTupleType = vtkm::Tuple<vtkm::cont::ArrayHandle<T, StorageTags>...>;
template <std::size_t... Is>
VTKM_CONT static ArrayTupleType GetArrayTupleImpl(vtkmstd::index_sequence<Is...>,
const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static ArrayTupleType GetArrayTupleImpl(
vtkmstd::index_sequence<Is...>,
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return ArrayTupleType(vtkm::cont::ArrayHandle<T, StorageTags>(Buffers<Is>(buffers))...);
}
public:
VTKM_CONT static ArrayTupleType GetArrayTuple(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static ArrayTupleType GetArrayTuple(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return GetArrayTupleImpl(IndexList{}, buffers);
}
@ -400,13 +372,13 @@ template <typename T, typename StorageTag>
struct Storage<T, vtkm::cont::StorageTagCompositeVec<StorageTag>> : Storage<T, StorageTag>
{
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
const vtkm::cont::ArrayHandle<T, StorageTag>& array)
const vtkm::cont::ArrayHandle<T, StorageTag>& array = vtkm::cont::ArrayHandle<T, StorageTag>{})
{
return vtkm::cont::internal::CreateBuffers(array);
}
VTKM_CONT static vtkm::Tuple<vtkm::cont::ArrayHandle<T, StorageTag>> GetArrayTuple(
const vtkm::cont::internal::Buffer* buffers)
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return vtkm::cont::ArrayHandle<T, StorageTag>(buffers);
}

@ -169,16 +169,26 @@ class Storage<T, StorageTagConcatenate<ST1, ST2>>
using ArrayHandleType1 = typename detail::ConcatinateTypeArg<T, ST1>::ArrayHandle;
using ArrayHandleType2 = typename detail::ConcatinateTypeArg<T, ST2>::ArrayHandle;
template <typename Buff>
VTKM_CONT static Buff* Buffers1(Buff* buffers)
struct Info
{
return buffers;
std::size_t NumBuffers1;
std::size_t NumBuffers2;
};
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> Buffers1(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
Info info = buffers[0].GetMetaData<Info>();
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + 1,
buffers.begin() + 1 + info.NumBuffers1);
}
template <typename Buff>
VTKM_CONT static Buff* Buffers2(Buff* buffers)
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> Buffers2(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers + SourceStorage1::GetNumberOfBuffers();
Info info = buffers[0].GetMetaData<Info>();
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + 1 + info.NumBuffers1,
buffers.end());
}
public:
@ -191,18 +201,14 @@ public:
vtkm::internal::ArrayPortalConcatenate<typename SourceStorage1::WritePortalType,
typename SourceStorage2::WritePortalType>;
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers()
{
return (SourceStorage1::GetNumberOfBuffers() + SourceStorage2::GetNumberOfBuffers());
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return (SourceStorage1::GetNumberOfValues(Buffers1(buffers)) +
SourceStorage2::GetNumberOfValues(Buffers2(buffers)));
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
@ -225,35 +231,42 @@ public:
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(SourceStorage1::CreateReadPortal(Buffers1(buffers), device, token),
SourceStorage2::CreateReadPortal(Buffers2(buffers), device, token));
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(SourceStorage1::CreateWritePortal(Buffers1(buffers), device, token),
SourceStorage2::CreateWritePortal(Buffers2(buffers), device, token));
}
VTKM_CONT static auto CreateBuffers(const ArrayHandleType1& array1,
const ArrayHandleType2& array2)
VTKM_CONT static auto CreateBuffers(const ArrayHandleType1& array1 = ArrayHandleType1{},
const ArrayHandleType2& array2 = ArrayHandleType2{})
-> decltype(vtkm::cont::internal::CreateBuffers())
{
return vtkm::cont::internal::CreateBuffers(array1, array2);
Info info;
info.NumBuffers1 = array1.GetBuffers().size();
info.NumBuffers2 = array2.GetBuffers().size();
return vtkm::cont::internal::CreateBuffers(info, array1, array2);
}
VTKM_CONT static const ArrayHandleType1 GetArray1(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static const ArrayHandleType1 GetArray1(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return ArrayHandleType1(Buffers1(buffers));
}
VTKM_CONT static const ArrayHandleType2 GetArray2(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static const ArrayHandleType2 GetArray2(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return ArrayHandleType2(Buffers2(buffers));
}

@ -24,6 +24,7 @@
#include <vtkmstd/integer_sequence.h>
#include <numeric>
#include <type_traits>
#include <utility>
@ -306,35 +307,22 @@ using GetWritePortalList =
std::declval<vtkm::cont::DeviceAdapterId>(),
std::declval<vtkm::cont::Token&>())))...>;
template <vtkm::IdComponent I, typename ArrayTupleType>
struct BufferIndexImpl
{
static constexpr vtkm::IdComponent Value()
{
return BufferIndexImpl<I - 1, ArrayTupleType>::Value() +
vtkm::TupleElement<I - 1, ArrayTupleType>::GetNumberOfBuffers();
}
};
template <typename ArrayTupleType>
struct BufferIndexImpl<0, ArrayTupleType>
{
static constexpr vtkm::IdComponent Value()
{
// One buffer reserved for metadata.
return 1;
}
};
template <typename DecoratorImplT>
template <typename DecoratorImplT, std::size_t NumArrays>
struct DecoratorMetaData
{
DecoratorImplT Implementation;
vtkm::Id NumberOfValues = 0;
std::array<std::size_t, NumArrays + 1> BufferOffsets;
DecoratorMetaData(const DecoratorImplT& implementation, vtkm::Id numValues)
template <typename... ArrayTs>
DecoratorMetaData(const DecoratorImplT& implementation,
vtkm::Id numValues,
const ArrayTs... arrays)
: Implementation(implementation)
, NumberOfValues(numValues)
{
auto numBuffers = { std::size_t{ 1 }, arrays.GetBuffers().size()... };
std::partial_sum(numBuffers.begin(), numBuffers.end(), this->BufferOffsets.begin());
}
DecoratorMetaData() = default;
@ -363,26 +351,22 @@ struct DecoratorStorageTraits
// size_t integral constants that index ArrayTs:
using IndexList = vtkmstd::make_index_sequence<sizeof...(ArrayTs)>;
// Returns the index into the buffers array for the array at the given index.
template <vtkm::IdComponent I>
static constexpr vtkm::IdComponent BufferIndex()
using MetaData = DecoratorMetaData<DecoratorImplT, sizeof...(ArrayTs)>;
static MetaData& GetMetaData(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return BufferIndexImpl<I, ArrayTupleType>::Value();
return buffers[0].GetMetaData<MetaData>();
}
// Converts a buffers array to the ArrayHandle at the given index.
template <vtkm::IdComponent I>
static vtkm::TupleElement<I, ArrayTupleType> BuffersToArray(
const vtkm::cont::internal::Buffer* buffers)
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return vtkm::TupleElement<I, ArrayTupleType>(buffers + BufferIndex<I>());
}
using MetaData = DecoratorMetaData<DecoratorImplT>;
static MetaData& GetMetaData(const vtkm::cont::internal::Buffer* buffers)
{
return buffers[0].GetMetaData<MetaData>();
const MetaData& metaData = GetMetaData(buffers);
std::vector<vtkm::cont::internal::Buffer> subBuffers(
buffers.begin() + metaData.BufferOffsets[I], buffers.begin() + metaData.BufferOffsets[I + 1]);
return vtkm::TupleElement<I, ArrayTupleType>(std::move(subBuffers));
}
// true_type/false_type depending on whether the decorator supports Allocate:
@ -440,7 +424,7 @@ struct DecoratorStorageTraits
// Static dispatch for calling AllocateSourceArrays on supported implementations:
VTKM_CONT [[noreturn]] static void CallAllocate(std::false_type,
vtkm::Id,
vtkm::cont::internal::Buffer*,
const std::vector<vtkm::cont::internal::Buffer>&,
vtkm::CopyFlag,
vtkm::cont::Token&,
ArrayTs...)
@ -450,7 +434,7 @@ struct DecoratorStorageTraits
VTKM_CONT static void CallAllocate(std::true_type,
vtkm::Id newSize,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token,
ArrayTs... arrays)
@ -463,11 +447,12 @@ struct DecoratorStorageTraits
// Portal construction methods. These actually create portals.
template <std::size_t... Indices>
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::Id numValues,
vtkmstd::index_sequence<Indices...>,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::Id numValues,
vtkmstd::index_sequence<Indices...>,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<WritePortalType>(
numValues,
@ -476,11 +461,12 @@ struct DecoratorStorageTraits
}
template <std::size_t... Indices>
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::Id numValues,
vtkmstd::index_sequence<Indices...>,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::Id numValues,
vtkmstd::index_sequence<Indices...>,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return CreatePortalDecorator<ReadPortalType>(
numValues,
@ -489,11 +475,12 @@ struct DecoratorStorageTraits
}
template <std::size_t... Indices>
VTKM_CONT static void AllocateSourceArrays(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token,
vtkmstd::index_sequence<Indices...>)
VTKM_CONT static void AllocateSourceArrays(
vtkm::Id numValues,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token,
vtkmstd::index_sequence<Indices...>)
{
CallAllocate(
IsAllocatable{}, numValues, buffers, preserve, token, BuffersToArray<Indices>(buffers)...);
@ -519,18 +506,14 @@ public:
using ReadPortalType = typename Traits::ReadPortalType;
using WritePortalType = typename Traits::WritePortalType;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers()
{
return Traits::template BufferIndex<static_cast<vtkm::IdComponent>(sizeof...(ArrayTs))>();
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return Traits::GetMetaData(buffers).NumberOfValues;
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
@ -545,17 +528,19 @@ public:
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return Traits::CreateReadPortal(
buffers, GetNumberOfValues(buffers), IndexList{}, device, token);
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return Traits::CreateWritePortal(
buffers, GetNumberOfValues(buffers), IndexList{}, device, token);
@ -564,7 +549,13 @@ public:
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer>
CreateBuffers(const DecoratorImplT& implementation, vtkm::Id numValues, const ArrayTs&... arrays)
{
return vtkm::cont::internal::CreateBuffers(MetaData(implementation, numValues), arrays...);
return vtkm::cont::internal::CreateBuffers(MetaData(implementation, numValues, arrays...),
arrays...);
}
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
{
return CreateBuffers(DecoratorImplT{}, 0, ArrayTs{}...);
}
};

@ -103,10 +103,15 @@ public:
// you actually try to use this read portal.
using ReadPortalType = vtkm::exec::internal::ArrayPortalDiscard<ValueType>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
{
DiscardMetaData metaData;
metaData.NumberOfValues = 0;
return vtkm::cont::internal::CreateBuffers(metaData);
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag,
vtkm::cont::Token&)
{
@ -114,12 +119,13 @@ public:
buffers[0].GetMetaData<DiscardMetaData>().NumberOfValues = numValues;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers[0].GetMetaData<DiscardMetaData>().NumberOfValues;
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
const ValueType&,
vtkm::Id,
vtkm::Id,
@ -128,16 +134,17 @@ public:
// Fill is a NO-OP.
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer*,
VTKM_CONT static ReadPortalType CreateReadPortal(const std::vector<vtkm::cont::internal::Buffer>&,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadValue("Cannot read from ArrayHandleDiscard.");
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
{
return WritePortalType(GetNumberOfValues(buffers));
}

@ -44,13 +44,8 @@ public:
{
}
// Copy constructor
VTKM_EXEC_CONT ArrayPortalExtractComponent(const ArrayPortalExtractComponent<PortalType>& src)
: Portal(src.Portal)
, Component(src.Component)
{
}
ArrayPortalExtractComponent(const ArrayPortalExtractComponent&) = default;
ArrayPortalExtractComponent(ArrayPortalExtractComponent&&) = default;
ArrayPortalExtractComponent& operator=(const ArrayPortalExtractComponent&) = default;
ArrayPortalExtractComponent& operator=(ArrayPortalExtractComponent&&) = default;
@ -103,15 +98,16 @@ class Storage<typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::Com
using SourceStorage = vtkm::cont::internal::Storage<SourceValueType, SourceStorageTag>;
public:
VTKM_CONT static vtkm::IdComponent ComponentIndex(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::IdComponent ComponentIndex(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers[0].GetMetaData<vtkm::IdComponent>();
}
template <typename Buff>
VTKM_CONT static Buff* SourceBuffers(Buff* buffers)
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> SourceBuffers(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers + 1;
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + 1, buffers.end());
}
using ReadPortalType =
@ -119,17 +115,13 @@ public:
using WritePortalType =
vtkm::internal::ArrayPortalExtractComponent<typename SourceStorage::WritePortalType>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers()
{
return SourceStorage::GetNumberOfBuffers() + 1;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return SourceStorage::GetNumberOfValues(SourceBuffers(buffers));
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
const ValueType&,
vtkm::Id,
vtkm::Id,
@ -139,31 +131,33 @@ public:
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
SourceStorage::ResizeBuffers(numValues, SourceBuffers(buffers), preserve, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(SourceStorage::CreateReadPortal(SourceBuffers(buffers), device, token),
ComponentIndex(buffers));
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(SourceStorage::CreateWritePortal(SourceBuffers(buffers), device, token),
ComponentIndex(buffers));
}
VTKM_CONT static auto CreateBuffers(vtkm::IdComponent componentIndex,
const ArrayHandleType& array)
VTKM_CONT static auto CreateBuffers(vtkm::IdComponent componentIndex = 0,
const ArrayHandleType& array = ArrayHandleType{})
-> decltype(vtkm::cont::internal::CreateBuffers())
{
return vtkm::cont::internal::CreateBuffers(componentIndex, array);

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