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

This commit is contained in:
Dave Pugmire 2024-03-28 12:45:20 -04:00
commit 6996466752
672 changed files with 33205 additions and 4575 deletions

1
.gitattributes vendored

@ -8,6 +8,7 @@
data/** filter=lfs diff=lfs merge=lfs -text data/** filter=lfs diff=lfs merge=lfs -text
/**/data/** filter=lfs diff=lfs merge=lfs -text /**/data/** filter=lfs diff=lfs merge=lfs -text
/**/images/** filter=lfs diff=lfs merge=lfs -text
*.cmake whitespace=tab-in-indent *.cmake whitespace=tab-in-indent
*.md whitespace=tab-in-indent whitespace=-blank-at-eol conflict-marker-size=79 -whitespace *.md whitespace=tab-in-indent whitespace=-blank-at-eol conflict-marker-size=79 -whitespace

2
.gitignore vendored

@ -1 +1,3 @@
.DS_Store .DS_Store
*vscode
.anari_deps

@ -30,7 +30,7 @@
- .docker_image - .docker_image
.ubuntu1604: &ubuntu1604 .ubuntu1604: &ubuntu1604
image: "kitware/vtkm:ci-ubuntu1604-20201016" image: "kitware/vtkm:ci-ubuntu1604-20230906"
extends: extends:
- .docker_image - .docker_image
@ -40,32 +40,32 @@
- .docker_image - .docker_image
.ubuntu1804: &ubuntu1804 .ubuntu1804: &ubuntu1804
image: "kitware/vtkm:ci-ubuntu1804-20210107" image: "kitware/vtkm:ci-ubuntu1804-20230906"
extends: extends:
- .docker_image - .docker_image
.ubuntu1804_cuda: &ubuntu1804_cuda .ubuntu1804_cuda: &ubuntu1804_cuda
image: "kitware/vtkm:ci-ubuntu1804_cuda11-20220919" image: "kitware/vtkm:ci-ubuntu1804_cuda11-20230906"
extends: extends:
- .docker_image - .docker_image
.ubuntu1804_cuda_kokkos: &ubuntu1804_cuda_kokkos .ubuntu1804_cuda_kokkos: &ubuntu1804_cuda_kokkos
image: "kitware/vtkm:ci-ubuntu1804_cuda11_kokkos-20230125" image: "kitware/vtkm:ci-ubuntu1804_cuda11_kokkos-20230906"
extends: extends:
- .docker_image - .docker_image
.ubuntu2004_doxygen: &ubuntu2004_doxygen .ubuntu2004_doxygen: &ubuntu2004_doxygen
image: "kitware/vtkm:ci-doxygen-20201016" image: "kitware/vtkm:ci-doxygen-20231020"
extends: extends:
- .docker_image - .docker_image
.ubuntu2004: &ubuntu2004 .ubuntu2004: &ubuntu2004
image: "kitware/vtkm:ci-ubuntu2004-20220623" image: "kitware/vtkm:ci-ubuntu2004-20230906"
extends: extends:
- .docker_image - .docker_image
.ubuntu2004_kokkos: &ubuntu2004_kokkos .ubuntu2004_kokkos: &ubuntu2004_kokkos
image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230705" image: "kitware/vtkm:ci-ubuntu2004_kokkos-20240119"
extends: extends:
- .docker_image - .docker_image
@ -75,7 +75,7 @@
- .docker_image - .docker_image
.opensuse: &opensuse .opensuse: &opensuse
image: "kitware/vtkm:ci-opensuse-20230619" image: "kitware/vtkm:ci-opensuse-20231121"
extends: extends:
- .docker_image - .docker_image
@ -107,12 +107,6 @@
when: on_success when: on_success
- when: never - when: never
.run_ascent_ci: &run_ascent_ci
rules:
- if: '$CI_PROJECT_PATH == "ecpcitest/vtk-m"'
when: on_success
- when: never
.run_crusher_ci: &run_crusher_ci .run_crusher_ci: &run_crusher_ci
rules: rules:
- if: '$CI_PROJECT_PATH == "ci/csc331_crusher/dev/vtk-m"' - if: '$CI_PROJECT_PATH == "ci/csc331_crusher/dev/vtk-m"'
@ -222,6 +216,10 @@ stages:
# CDash files. # CDash files.
- build/DartConfiguration.tcl - build/DartConfiguration.tcl
# Users guide
- build/docs/users-guide/html
- build/docs/users-guide/latex
.cmake_test_artifacts: &cmake_test_artifacts .cmake_test_artifacts: &cmake_test_artifacts
artifacts: artifacts:
expire_in: 24 hours expire_in: 24 hours
@ -237,7 +235,6 @@ stages:
include: include:
- local: '/.gitlab/ci/ascent.yml'
- local: '/.gitlab/ci/crusher.yml' - local: '/.gitlab/ci/crusher.yml'
- local: '/.gitlab/ci/centos7.yml' - local: '/.gitlab/ci/centos7.yml'
- local: '/.gitlab/ci/centos8.yml' - local: '/.gitlab/ci/centos8.yml'

@ -1,102 +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.
##
##=============================================================================
# Ad-hoc build that runs in the ECP Hardware, concretely in OLCF Ascent.
.ascent_gcc_cuda:
variables:
CCACHE_BASEDIR: "/gpfs/wolf/"
CCACHE_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/ccache"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_NOHASHDIR: "true"
CC: "gcc"
CXX: "g++"
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_GENERATOR: "Ninja"
CUDAHOSTCXX: "g++"
CUSTOM_CI_BUILDS_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/vtk-m"
VTKM_SETTINGS: cuda+ascent+ccache
JOB_MODULES: >-
git-lfs
zstd
cuda/11.4.2
gcc/10.2.0
ninja
spectrum-mpi
lsf-tools
cmake
interruptible: true
.setup_env_ecpci: &setup_env_ecpci |
module purge
module load ${JOB_MODULES}
module list
export PATH="/gpfs/wolf/csc331/scratch/vbolea/ci/utils:$PATH"
build:ascent_gcc_cuda:
stage: build
tags: [olcf, ascent, batch]
extends:
- .ascent_gcc_cuda
- .run_ascent_ci
- .cmake_build_artifacts
variables:
SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 -alloc_flags smt1
timeout: 125 minutes
before_script:
- *setup_env_ecpci
- ccache -z
- git remote add lfs https://gitlab.kitware.com/vtk/vtk-m.git
- git fetch lfs
- git-lfs install
- git-lfs pull lfs
script:
# Each Ascent (Summit) node has 172 threads (43 cores). SMT1 is needed to
# avoid L1 cache pollution among different processes. Thus, using 40 cores
# seems a reasonable choice which leaves a couple of cores for system processes.
- CTEST_MAX_PARALLELISM=40 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
- ctest -VV -S .gitlab/ci/ctest_configure.cmake
- GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c40 -bpacked:40 ctest -VV -S .gitlab/ci/ctest_build.cmake
after_script:
- *setup_env_ecpci
- ccache -s
- ctest -VV -S .gitlab/ci/ctest_submit_build.cmake
test:ascent_gcc_cuda:
stage: test
tags: [olcf, ascent, batch]
extends:
- .ascent_gcc_cuda
- .run_ascent_ci
- .cmake_test_artifacts
needs:
- build:ascent_gcc_cuda
dependencies:
- build:ascent_gcc_cuda
variables:
# For tests we want to use a small number of proccesses, for some reason
# a higher parallelism number tend to results in test malfunctions.
CTEST_MAX_PARALLELISM: 4
# We need this to skip ctest_submit from being run inside a jsrun job
GITLAB_CI_EMULATION: 1
SCHEDULER_PARAMETERS: -P CSC331 -W 1:00 -nnodes 1 -alloc_flags gpudefault
timeout: 65 minutes
before_script:
- *setup_env_ecpci
script:
- cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
- jsrun -n1 -a1 -g1 -c1 ctest -VV -S .gitlab/ci/ctest_test.cmake
after_script:
- *setup_env_ecpci
- ctest -VV -S .gitlab/ci/ctest_submit_test.cmake

@ -41,8 +41,10 @@ test:centos8_sanitizer:
variables: variables:
OMP_NUM_THREADS: 4 OMP_NUM_THREADS: 4
CTEST_MEMORYCHECK_TYPE: LeakSanitizer CTEST_MEMORYCHECK_TYPE: LeakSanitizer
CTEST_EXCLUSIONS: smoke_test_built_against_test_install CTEST_EXCLUSIONS: >-
smoke_test_cmake_built_against_test_install
smoke_test_make_built_against_test_install
smoke_test_pkgconfig_make_built_against_test_install
dependencies: dependencies:
- build:centos8_sanitizer - build:centos8_sanitizer
needs: needs:

@ -1,56 +0,0 @@
#!/usr/bin/env python3
##=============================================================================
##
## 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.
##
##=============================================================================
import json
import ssl
import sys
import urllib.request
class ecpci_url_reader:
def __init__(self, base_url, token):
self.base_url = base_url
self.token = token
def to_string(self, url):
opener = urllib.request.build_opener(
urllib.request.HTTPSHandler(
context=ssl._create_unverified_context()))
opener.addheaders = [('PRIVATE-TOKEN', token)]
return opener.open(base_url + url).read().decode('utf-8')
def to_json(self, url):
return json.loads(self.to_string(url))
base_url = sys.argv[1]
commit = sys.argv[2]
token = sys.argv[3]
handler = ecpci_url_reader(base_url, token)
commit_info = handler.to_json("/repository/commits/" + commit)
last_pipeline_id = str(commit_info['last_pipeline']['id'])
jobs = handler.to_json("/pipelines/" + last_pipeline_id + "/jobs")
build_job_id = str(jobs[1]['id'])
test_job_id = str(jobs[0]['id'])
print("ECPCITEST CONFIGURE OUTPUT============================================")
print(handler.to_string("/jobs/" + build_job_id + "/trace"))
print("ECPCITEST CONFIGURE END===============================================")
print("ECPCITEST TEST OUTPUT=================================================")
print(handler.to_string("/jobs/" + test_job_id + "/trace"))
print("ECPCITEST TEST OUTPUT END=============================================")

@ -1,80 +0,0 @@
#!/bin/bash -e
# shellcheck disable=SC2155
##=============================================================================
##
## 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.
##
##=============================================================================
declare -r POLL_INTERVAL_SECONDS="10"
function fetch_commit_status()
{
local -r url="$1"
local -r commit="$2"
local output=$(curl --insecure --silent "${url}/repository/commits/${commit}" \
| tr ',{}[]' '\n' \
| grep -Po -m1 '(?<=^"status":")\w+(?=")' \
)
# No status means that the pipeline has not being created yet
[ -z "$output" ] && output="empty"
echo "$output"
}
function print_pipeline_url()
{
local -r url="$1"
local -r commit="$2"
local web_url=$(curl --insecure --silent "${url}" \
| tr ',{}[]' '\n' \
| grep -Po -m1 '(?<=^"web_url":").+(?=")' \
)
local pipeline_id=$(curl --insecure --silent "${url}/repository/commits/${commit}" \
| tr ',{}[]' '\n' \
| grep -Po '(?<=^"id":)\d+$' \
)
echo "######################################################################"
echo "ECP Pipeline: ${web_url}/-/pipelines/$pipeline_id"
echo "######################################################################"
}
function wait_commit_pipeline_status()
{
local -r base_url="$1"
local -r commit="$2"
local is_url_printed="no"
while true
do
local ret="$(fetch_commit_status "$base_url" "$commit")"
if [ "$ret" != "empty" ] && [ "$is_url_printed" == "no" ]
then
print_pipeline_url "$base_url" "$commit"
is_url_printed="yes"
fi
case "$ret" in
success)
return 0 ;;
failed|canceled|skipped)
echo "ERROR: The pipeline exited with \`${ret}\` status" > /dev/stderr
return 1 ;;
esac
sleep "$POLL_INTERVAL_SECONDS"
done
}
wait_commit_pipeline_status "$1" "$2"

@ -53,6 +53,9 @@ foreach(option IN LISTS options)
elseif(no_rendering STREQUAL option) elseif(no_rendering STREQUAL option)
set(VTKm_ENABLE_RENDERING "OFF" CACHE STRING "") set(VTKm_ENABLE_RENDERING "OFF" CACHE STRING "")
elseif(anari STREQUAL option)
set(VTKm_ENABLE_ANARI "ON" CACHE STRING "")
elseif(no_testing STREQUAL option) elseif(no_testing STREQUAL option)
set(VTKm_ENABLE_TESTING "OFF" CACHE STRING "") set(VTKm_ENABLE_TESTING "OFF" CACHE STRING "")
set(VTKm_ENABLE_TESTING_LIBRARY "OFF" CACHE STRING "") set(VTKm_ENABLE_TESTING_LIBRARY "OFF" CACHE STRING "")
@ -63,6 +66,7 @@ foreach(option IN LISTS options)
elseif(docs STREQUAL option) elseif(docs STREQUAL option)
set(VTKm_ENABLE_DOCUMENTATION "ON" CACHE STRING "") set(VTKm_ENABLE_DOCUMENTATION "ON" CACHE STRING "")
set(VTKm_USERS_GUIDE_INCLUDE_TODOS "OFF" CACHE STRING "")
elseif(benchmarks STREQUAL option) elseif(benchmarks STREQUAL option)
set(VTKm_ENABLE_BENCHMARKS "ON" CACHE STRING "") set(VTKm_ENABLE_BENCHMARKS "ON" CACHE STRING "")
@ -116,10 +120,6 @@ foreach(option IN LISTS options)
set(CMAKE_HIP_FLAGS "-O0 " CACHE STRING "") set(CMAKE_HIP_FLAGS "-O0 " CACHE STRING "")
set(CMAKE_HIP_FLAGS_RELWITHDEBINFO "-g" CACHE STRING "") set(CMAKE_HIP_FLAGS_RELWITHDEBINFO "-g" CACHE STRING "")
elseif(ascent STREQUAL option)
set(CMAKE_C_FLAGS "-mcpu=power9" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-mcpu=power9" CACHE STRING "")
elseif(ccache STREQUAL option) elseif(ccache STREQUAL option)
find_program(CCACHE_COMMAND NAMES ccache REQUIRED) find_program(CCACHE_COMMAND NAMES ccache REQUIRED)

@ -37,20 +37,32 @@ set(test_exclusions
$ENV{CTEST_EXCLUSIONS} $ENV{CTEST_EXCLUSIONS}
) )
string(REPLACE " " ";" test_exclusions "${test_exclusions}")
string(REPLACE ";" "|" test_exclusions "${test_exclusions}") string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
if (test_exclusions) if (test_exclusions)
set(test_exclusions "(${test_exclusions})") set(test_exclusions EXCLUDE "(${test_exclusions})")
endif () endif ()
if (DEFINED ENV{TEST_INCLUSIONS})
set(test_inclusions INCLUDE $ENV{TEST_INCLUSIONS})
unset(test_exclusions)
endif()
set(PARALLEL_LEVEL "10")
if (DEFINED ENV{CTEST_MAX_PARALLELISM})
set(PARALLEL_LEVEL $ENV{CTEST_MAX_PARALLELISM})
endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
set(junit_args OUTPUT_JUNIT "${CTEST_BINARY_DIRECTORY}/junit.xml") set(junit_args OUTPUT_JUNIT "${CTEST_BINARY_DIRECTORY}/junit.xml")
endif() endif()
# reduced parallel level so we don't exhaust system resources # reduced parallel level so we don't exhaust system resources
ctest_memcheck( ctest_memcheck(
PARALLEL_LEVEL "4" PARALLEL_LEVEL ${PARALLEL_LEVEL}
RETURN_VALUE test_result RETURN_VALUE test_result
EXCLUDE "${test_exclusions}" ${test_exclusions}
${test_inclusions}
DEFECT_COUNT defects DEFECT_COUNT defects
${junit_args} ${junit_args}
) )

@ -24,13 +24,23 @@ RUN zypper refresh && \
git-lfs \ git-lfs \
hdf5-devel \ hdf5-devel \
libgomp1 \ libgomp1 \
mpich \ make \
mpich-devel \
ninja \ ninja \
python311 \ python311 \
python311-scipy \ python311-scipy \
tbb-devel && \ tbb-devel && \
zypper clean --all zypper clean --all
ARG MPICH_VERSION=4.1.1
RUN curl -s -L https://www.mpich.org/static/downloads/${MPICH_VERSION}/mpich-${MPICH_VERSION}.tar.gz | tar xzf - && \
cd mpich-${MPICH_VERSION} && \
./configure \
--disable-fortran \
--prefix=/usr/local \
--with-device=ch3:sock:tcp && \
make -j $(nproc) && \
make install && \
rm -rf mpich-${MPICH_VERSION}
# Need to run git-lfs install manually on system packaged version # Need to run git-lfs install manually on system packaged version
RUN git-lfs install RUN git-lfs install

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM ubuntu:16.04 FROM ubuntu:16.04
LABEL maintainer "Robert Maynard<robert.maynard@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libtbb-dev \ libtbb-dev \
make \ make \
ninja-build \ ninja-build \
pkg-config \
software-properties-common \ software-properties-common \
ssh ssh

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM ubuntu:18.04 FROM ubuntu:18.04
LABEL maintainer "Robert Maynard<robert.maynard@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -25,8 +25,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libomp-dev \ libomp-dev \
libtbb-dev \ libtbb-dev \
libhdf5-dev \ libhdf5-dev \
make \
mpich \ mpich \
ninja-build \ ninja-build \
pkg-config \
software-properties-common software-properties-common
# extra dependencies for charm machine # extra dependencies for charm machine

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM nvidia/cuda:11.7.1-devel-ubuntu18.04 FROM nvidia/cuda:11.7.1-devel-ubuntu18.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez <vicente.bolea@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -22,8 +22,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libmpich-dev \ libmpich-dev \
libomp-dev \ libomp-dev \
libtbb-dev \ libtbb-dev \
make \
mpich \ mpich \
ninja-build \ ninja-build \
pkg-config \
python3 \ python3 \
python3-scipy \ python3-scipy \
&& \ && \

@ -10,8 +10,8 @@
## ##
##============================================================================= ##=============================================================================
FROM nvidia/cuda:11.6.1-devel-ubuntu18.04 FROM nvidia/cuda:11.6.2-devel-ubuntu18.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@ -19,7 +19,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \ g++ \
git \ git \
git-lfs \ git-lfs \
make \
ninja-build \ ninja-build \
pkg-config \
&& \ && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM ubuntu:20.04 FROM ubuntu:20.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
ENV TZ=America/New_York ENV TZ=America/New_York
@ -26,8 +26,10 @@ RUN apt update && DEBIAN_FRONTEND="noninteractive" apt install -y --no-install-r
libomp-dev \ libomp-dev \
libtbb-dev \ libtbb-dev \
libhdf5-dev \ libhdf5-dev \
make \
mpich \ mpich \
ninja-build \ ninja-build \
pkg-config \
python \ python \
python3-scipy \ python3-scipy \
software-properties-common && \ software-properties-common && \

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM ubuntu:20.04 FROM ubuntu:20.04
LABEL maintainer "Robert Maynard<robert.maynard@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
@ -26,9 +26,17 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
libtbb-dev \ libtbb-dev \
mpich \ mpich \
ninja-build \ ninja-build \
python3-pip \
rsync \ rsync \
ssh \ software-properties-common \
software-properties-common ssh
RUN python3 -m pip install \
breathe \
sphinx \
sphinxcontrib-moderncmakedomain \
sphinxcontrib-packages \
sphinx-rtd-theme
# Need to run git-lfs install manually on ubuntu based images when using the # Need to run git-lfs install manually on ubuntu based images when using the
# system packaged version # system packaged version

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM rocm/dev-ubuntu-20.04 FROM rocm/dev-ubuntu-20.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt update && \ RUN apt update && \
@ -22,8 +22,10 @@ RUN apt update && \
git-lfs \ git-lfs \
libmpich-dev \ libmpich-dev \
libomp-dev \ libomp-dev \
make \
mpich \ mpich \
ninja-build \ ninja-build \
pkg-config \
rsync \ rsync \
ssh \ ssh \
rocthrust-dev \ rocthrust-dev \

@ -11,7 +11,7 @@
##============================================================================= ##=============================================================================
FROM ubuntu:20.04 FROM ubuntu:20.04
LABEL maintainer "Sujin Philip<sujin.philip@kitware.com>" LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects # Base dependencies for building VTK-m projects
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
@ -22,8 +22,10 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
git-lfs \ git-lfs \
libmpich-dev \ libmpich-dev \
libomp-dev \ libomp-dev \
make \
mpich \ mpich \
ninja-build \ ninja-build \
pkg-config \
rsync \ rsync \
ssh \ ssh \
software-properties-common software-properties-common
@ -52,3 +54,25 @@ RUN mkdir -p /opt/kokkos/build && \
cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/kokkos -DCMAKE_CXX_FLAGS=-fPIC -DKokkos_ENABLE_SERIAL=ON ../kokkos-$KOKKOS_VERSION &&\ cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/kokkos -DCMAKE_CXX_FLAGS=-fPIC -DKokkos_ENABLE_SERIAL=ON ../kokkos-$KOKKOS_VERSION &&\
ninja all && \ ninja all && \
ninja install ninja install
# Build and install ANARI SDK
WORKDIR /opt/anari/src
ARG ANARI_VERSION=0.8.0
RUN curl -L https://github.com/KhronosGroup/ANARI-SDK/archive/refs/tags/v$ANARI_VERSION.tar.gz | tar xzv && \
cmake -GNinja \
-S ANARI-SDK-$ANARI_VERSION \
-B build \
-DBUILD_CTS=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_HELIDE_DEVICE=ON \
-DBUILD_REMOTE_DEVICE=OFF \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTING=OFF \
-DBUILD_VIEWER=OFF \
-DCMAKE_INSTALL_PREFIX=/opt/anari \
-DINSTALL_VIEWER_LIBRARY=OFF && \
cmake --build build && \
cmake --install build && \
rm -rf *
WORKDIR /root

@ -16,7 +16,7 @@ set -e
set -x set -x
# data is expected to be a string of the form YYYYMMDD # data is expected to be a string of the form YYYYMMDD
readonly date="$1" readonly date="$(date +%Y%m%d)"
cd centos7/cuda10.2 cd centos7/cuda10.2
sudo docker build -t kitware/vtkm:ci-centos7_cuda10.2-$date . sudo docker build -t kitware/vtkm:ci-centos7_cuda10.2-$date .
@ -30,6 +30,10 @@ cd rhel8/cuda10.2
sudo docker build -t kitware/vtkm:ci-rhel8_cuda10.2-$date . sudo docker build -t kitware/vtkm:ci-rhel8_cuda10.2-$date .
cd ../.. cd ../..
cd opensuse
sudo docker build -t kitware/vtkm:ci-opensuse-$date .
cd ..
cd ubuntu1604/base cd ubuntu1604/base
sudo docker build -t kitware/vtkm:ci-ubuntu1604-$date . sudo docker build -t kitware/vtkm:ci-ubuntu1604-$date .
cd ../.. cd ../..
@ -42,7 +46,7 @@ cd ubuntu1804/base
sudo docker build -t kitware/vtkm:ci-ubuntu1804-$date . sudo docker build -t kitware/vtkm:ci-ubuntu1804-$date .
cd ../.. cd ../..
cd ubuntu1804/cuda11.1 cd ubuntu1804/cuda
sudo docker build -t kitware/vtkm:ci-ubuntu1804_cuda11.1-$date . sudo docker build -t kitware/vtkm:ci-ubuntu1804_cuda11.1-$date .
cd ../.. cd ../..
@ -50,6 +54,10 @@ cd ubuntu1804/kokkos-cuda
sudo docker build -t kitware/vtkm:ci-ubuntu1804_cuda11_kokkos-$date . sudo docker build -t kitware/vtkm:ci-ubuntu1804_cuda11_kokkos-$date .
cd ../.. cd ../..
cd ubuntu2004/base/
sudo docker build -t kitware/vtkm:ci-ubuntu2004-$date .
cd ../..
cd ubuntu2004/doxygen/ cd ubuntu2004/doxygen/
sudo docker build -t kitware/vtkm:ci-doxygen-$date . sudo docker build -t kitware/vtkm:ci-doxygen-$date .
cd ../.. cd ../..
@ -58,6 +66,10 @@ cd ubuntu2004/kokkos
sudo docker build -t kitware/vtkm:ci-ubuntu2004_kokkos-$date . sudo docker build -t kitware/vtkm:ci-ubuntu2004_kokkos-$date .
cd ../.. cd ../..
cd ubuntu2004/kokkos-hip
sudo docker build -t kitware/vtkm:ci-ubuntu2004_hip_kokkos-$date .
cd ../..
# sudo docker login --username=<docker_hub_name> # sudo docker login --username=<docker_hub_name>
sudo docker push kitware/vtkm # sudo docker push kitware/vtkm
sudo docker system prune # sudo docker system prune

@ -10,7 +10,16 @@
## ##
##============================================================================= ##=============================================================================
.doxygen_submit: &doxygen_submit .upload_doxygen_script: &upload_doxygen_script
- chmod 400 $DOC_KEY_FILE
- rsync -rtv --delete -e "ssh -i $DOC_KEY_FILE -o StrictHostKeyChecking=no" build/docs/doxygen/html/ "kitware@web.kitware.com:vtkm_documentation/$DOXYGEN_UPLOAD_REMOTE_PATH"
.build_doxygen_script: &build_doxygen_script
- cmake --build "${CI_PROJECT_DIR}/build" --target docs/doxygen
- cmake --build "${CI_PROJECT_DIR}/build" --target VTKmUsersGuideHTML
- cmake --build "${CI_PROJECT_DIR}/build" --target VTKmUsersGuideLaTeX
.build_docs: &build_docs
stage: build stage: build
tags: tags:
- build - build
@ -18,19 +27,27 @@
- docker - docker
- linux-x86_64 - linux-x86_64
before_script: before_script:
- "cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake" - cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake
- "ctest -VV -S .gitlab/ci/ctest_configure.cmake" - ctest -VV -S .gitlab/ci/ctest_configure.cmake
script:
- doxygen build/docs/doxyfile
- chmod 400 $DOC_KEY_FILE
- rsync -tv --recursive --delete -e "ssh -i $DOC_KEY_FILE -o StrictHostKeyChecking=no" build/docs/doxygen/html/ "kitware@web.kitware.com:vtkm_documentation/$DOXYGEN_UPLOAD_REMOTE_PATH"
timeout: 30 minutes timeout: 30 minutes
interruptible: true interruptible: true
variables: variables:
CMAKE_BUILD_TYPE: Release CMAKE_BUILD_TYPE: Release
VTKM_SETTINGS: "tbb+openmp+mpi+shared+docs" VTKM_SETTINGS: "tbb+openmp+mpi+shared+docs"
docs:nightly: build:docs-continuous:
script:
- *build_doxygen_script
extends:
- .build_docs
- .cmake_build_artifacts
- .run_automatically
- .ubuntu2004_doxygen
build:docs-master:
script:
- *build_doxygen_script
- *upload_doxygen_script
environment: environment:
name: doxygen-nightly name: doxygen-nightly
url: https://docs-m.vtk.org/nightly/ url: https://docs-m.vtk.org/nightly/
@ -39,12 +56,16 @@ docs:nightly:
when: on_success when: on_success
- when: never - when: never
extends: extends:
- .build_docs
- .cmake_build_artifacts
- .ubuntu2004_doxygen - .ubuntu2004_doxygen
- .doxygen_submit
variables: variables:
DOXYGEN_UPLOAD_REMOTE_PATH: "nightly" DOXYGEN_UPLOAD_REMOTE_PATH: "nightly"
docs:latest: build:docs-latest:
script:
- *build_doxygen_script
- *upload_doxygen_script
environment: environment:
name: doxygen-latest name: doxygen-latest
url: https://docs-m.vtk.org/latest/index.html url: https://docs-m.vtk.org/latest/index.html
@ -53,7 +74,8 @@ docs:latest:
when: on_success when: on_success
- when: never - when: never
extends: extends:
- .build_docs
- .cmake_build_artifacts
- .ubuntu2004_doxygen - .ubuntu2004_doxygen
- .doxygen_submit
variables: variables:
DOXYGEN_UPLOAD_REMOTE_PATH: "latest" DOXYGEN_UPLOAD_REMOTE_PATH: "latest"

@ -90,6 +90,10 @@ test:macos_xcode14:
- "ctest $CTEST_TIMEOUT -VV -S .gitlab/ci/ctest_test.cmake" - "ctest $CTEST_TIMEOUT -VV -S .gitlab/ci/ctest_test.cmake"
extends: extends:
- .cmake_test_artifacts - .cmake_test_artifacts
variables:
CTEST_EXCLUSIONS: >-
smoke_test_make_built_against_test_install
smoke_test_pkgconfig_make_built_against_test_install
.macos_build_tags: .macos_build_tags:
tags: tags:

@ -122,3 +122,5 @@ test:ubuntu1604_clang5:
- build:ubuntu1604_clang5 - build:ubuntu1604_clang5
needs: needs:
- build:ubuntu1604_clang5 - build:ubuntu1604_clang5
variables:
CTEST_EXCLUSIONS: "make_built_against_test_install"

@ -22,7 +22,8 @@ build:ubuntu2004_kokkos:
- .run_automatically - .run_automatically
variables: variables:
CMAKE_BUILD_TYPE: RelWithDebInfo CMAKE_BUILD_TYPE: RelWithDebInfo
VTKM_SETTINGS: "kokkos+shared+64bit_floats" CMAKE_PREFIX_PATH: "/opt/anari"
VTKM_SETTINGS: "kokkos+shared+64bit_floats+rendering+anari"
test:ubuntu2004_kokkos: test:ubuntu2004_kokkos:
tags: tags:
@ -81,35 +82,9 @@ test:ubuntu2004_hip_kokkos:
- .run_upstream_branches - .run_upstream_branches
variables: variables:
CTEST_MAX_PARALLELISM: 1 CTEST_MAX_PARALLELISM: 1
TEST_EXCLUSIONS: "UnitTestWorkletParticleAdvection" CTEST_EXCLUSIONS: "UnitTestWorkletParticleAdvection"
dependencies: dependencies:
- build:ubuntu2004_hip_kokkos - build:ubuntu2004_hip_kokkos
needs: needs:
- build:ubuntu2004_hip_kokkos - build:ubuntu2004_hip_kokkos
timeout: 3 hours timeout: 3 hours
# This is only for merge-requests
build:ascent:
stage: build
variables:
BRANCH_NAME: "mr${CI_MERGE_REQUEST_IID}-${CI_COMMIT_REF_NAME}"
ASCENT_REST_URL: "https://code.ornl.gov/api/v4/projects/7035"
ASCENT_GIT_URL: "https://vbolea:${ECPTEST_TOKEN}@code.ornl.gov/ecpcitest/vtk-m.git"
tags:
- vtkm
- docker
- build
- linux-x86_64
extends:
- .ubuntu2004
- .run_only_merge_requests
script:
# A new commit is needed to symbolize a restart of a build from the same original commit
- .gitlab/ci/config/ecpci-amend-commit.sh "NEW_COMMIT_SHA"
- .gitlab/ci/config/ecpci-push-branch.sh "$ASCENT_GIT_URL" "$BRANCH_NAME"
- timeout 130m .gitlab/ci/config/ecpci-wait-commit-status.sh "$ASCENT_REST_URL" "$(cat NEW_COMMIT_SHA)"
after_script:
- .gitlab/ci/config/ecpci-remove-branch.sh "$ASCENT_GIT_URL" "$BRANCH_NAME" || true
- .gitlab/ci/config/ecpci-fetch-commit-trace.py "$ASCENT_REST_URL" "$(cat NEW_COMMIT_SHA)" "$ECPTEST_TOKEN"
timeout: 150 minutes
interruptible: true

43
.readthedocs.yaml Normal file

@ -0,0 +1,43 @@
##=============================================================================
##
## 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.
##
##=============================================================================
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
apt_packages:
- cmake
- make
- git-lfs
tools:
python: '3.10'
jobs:
post_install:
- git lfs install --local
- git lfs fetch --include "*.png"
- git lfs checkout *.png
- cmake -B build -S . -DVTKm_ENABLE_DOCUMENTATION=ON -DVTKm_ENABLE_USERS_GUIDE=ON -DVTKm_USERS_GUIDE_INCLUDE_TODOS=OFF
- cmake --build build --target VTKmDoxygenDocs
- cp -f ./build/docs/users-guide/VTKmUsersGuideHTML.cache/conf.py docs/users-guide/conf.py
sphinx:
configuration: docs/users-guide/conf.py
python:
install:
- requirements: docs/users-guide/requirements.txt
formats:
- epub
- pdf

395
CMake/FindSphinx.cmake Normal file

@ -0,0 +1,395 @@
# This find module originally created by Jeroen Koekkoek.
# Copyright (c) 2023, Jeroen Koekkoek
#
# This file is covered by a BSD 3-Clause License.
# See https://github.com/k0ekk0ek/cmake-sphinx/blob/master/LICENSE for details.
include(FindPackageHandleStandardArgs)
macro(_Sphinx_find_executable _exe)
string(TOUPPER "${_exe}" _uc)
# sphinx-(build|quickstart)-3 x.x.x
# FIXME: This works on Fedora (and probably most other UNIX like targets).
# Windows targets and PIP installs might need some work.
find_program(
SPHINX_${_uc}_EXECUTABLE
NAMES "sphinx-${_exe}-3" "sphinx-${_exe}" "sphinx-${_exe}.exe")
mark_as_advanced(SPHINX_${_uc}_EXECUTABLE)
if(SPHINX_${_uc}_EXECUTABLE)
execute_process(
COMMAND "${SPHINX_${_uc}_EXECUTABLE}" --version
RESULT_VARIABLE _result
OUTPUT_VARIABLE _output
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(_result EQUAL 0 AND _output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$")
set(SPHINX_${_uc}_VERSION "${CMAKE_MATCH_1}")
endif()
if(NOT TARGET Sphinx::${_exe})
add_executable(Sphinx::${_exe} IMPORTED GLOBAL)
set_target_properties(Sphinx::${_exe} PROPERTIES
IMPORTED_LOCATION "${SPHINX_${_uc}_EXECUTABLE}")
endif()
set(Sphinx_${_exe}_FOUND TRUE)
else()
set(Sphinx_${_exe}_FOUND FALSE)
endif()
unset(_uc)
endmacro()
macro(_Sphinx_find_module _name _module)
string(TOUPPER "${_name}" _Sphinx_uc)
if(SPHINX_PYTHON_EXECUTABLE)
execute_process(
COMMAND ${SPHINX_PYTHON_EXECUTABLE} -m ${_module} --version
RESULT_VARIABLE _result
OUTPUT_VARIABLE _output
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(_result EQUAL 0)
if(_output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$")
set(SPHINX_${_Sphinx_uc}_VERSION "${CMAKE_MATCH_1}")
endif()
if(NOT TARGET Sphinx::${_name})
set(SPHINX_${_Sphinx_uc}_EXECUTABLE "${SPHINX_PYTHON_EXECUTABLE} -m ${_module}")
add_executable(Sphinx::${_name} IMPORTED GLOBAL)
set_target_properties(Sphinx::${_name} PROPERTIES
IMPORTED_LOCATION "${SPHINX_PYTHON_EXECUTABLE}")
endif()
set(Sphinx_${_name}_ARGS -m ${_module})
set(Sphinx_${_name}_FOUND TRUE)
else()
set(Sphinx_${_name}_FOUND FALSE)
endif()
else()
set(Sphinx_${_name}_FOUND FALSE)
endif()
unset(_Sphinx_uc)
endmacro()
macro(_Sphinx_find_extension _ext)
if(SPHINX_PYTHON_EXECUTABLE)
execute_process(
COMMAND ${SPHINX_PYTHON_EXECUTABLE} -c "import ${_ext}"
RESULT_VARIABLE _result)
if(_result EQUAL 0)
set(Sphinx_${_ext}_FOUND TRUE)
else()
set(Sphinx_${_ext}_FOUND FALSE)
endif()
endif()
endmacro()
#
# Find sphinx-build and sphinx-quickstart.
#
# Find sphinx-build shim.
_Sphinx_find_executable(build)
if(SPHINX_BUILD_EXECUTABLE)
# Find sphinx-quickstart shim.
_Sphinx_find_executable(quickstart)
# Locate Python executable
if(CMAKE_HOST_WIN32)
# script-build on Windows located under (when PIP is used):
# C:/Program Files/PythonXX/Scripts
# C:/Users/username/AppData/Roaming/Python/PythonXX/Sripts
#
# Python modules are installed under:
# C:/Program Files/PythonXX/Lib
# C:/Users/username/AppData/Roaming/Python/PythonXX/site-packages
#
# To verify a given module is installed, use the Python base directory
# and test if either Lib/module.py or site-packages/module.py exists.
get_filename_component(_Sphinx_directory "${SPHINX_BUILD_EXECUTABLE}" DIRECTORY)
get_filename_component(_Sphinx_directory "${_Sphinx_directory}" DIRECTORY)
if(EXISTS "${_Sphinx_directory}/python.exe")
set(SPHINX_PYTHON_EXECUTABLE "${_Sphinx_directory}/python.exe")
endif()
unset(_Sphinx_directory)
else()
file(READ "${SPHINX_BUILD_EXECUTABLE}" _Sphinx_script)
if(_Sphinx_script MATCHES "^#!([^\n]+)")
string(STRIP "${CMAKE_MATCH_1}" _Sphinx_shebang)
if(EXISTS "${_Sphinx_shebang}")
set(SPHINX_PYTHON_EXECUTABLE "${_Sphinx_shebang}")
endif()
endif()
unset(_Sphinx_script)
unset(_Sphinx_shebang)
endif()
endif()
if(NOT SPHINX_PYTHON_EXECUTABLE)
# Python executable cannot be extracted from shim shebang or path if e.g.
# virtual environments are used, fallback to find package. Assume the
# correct installation is found, the setup is probably broken in more ways
# than one otherwise.
find_package(Python3 QUIET COMPONENTS Interpreter)
if(TARGET Python3::Interpreter)
set(SPHINX_PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
# Revert to "python -m sphinx" if shim cannot be found.
if(NOT SPHINX_BUILD_EXECUTABLE)
_Sphinx_find_module(build sphinx)
_Sphinx_find_module(quickstart sphinx.cmd.quickstart)
endif()
endif()
endif()
#
# Verify components are available.
#
if(SPHINX_BUILD_VERSION)
# Breathe is required for Exhale
if("exhale" IN_LIST Sphinx_FIND_COMPONENTS AND NOT
"breathe" IN_LIST Sphinx_FIND_COMPONENTS)
list(APPEND Sphinx_FIND_COMPONENTS "breathe")
endif()
foreach(_Sphinx_component IN LISTS Sphinx_FIND_COMPONENTS)
if(_Sphinx_component STREQUAL "build")
# Do nothing, sphinx-build is always required.
continue()
elseif(_Sphinx_component STREQUAL "quickstart")
# Do nothing, sphinx-quickstart is optional, but looked up by default.
continue()
endif()
_Sphinx_find_extension(${_Sphinx_component})
endforeach()
unset(_Sphinx_component)
#
# Verify both executables are part of the Sphinx distribution.
#
if(SPHINX_QUICKSTART_VERSION AND NOT SPHINX_BUILD_VERSION STREQUAL SPHINX_QUICKSTART_VERSION)
message(FATAL_ERROR "Versions for sphinx-build (${SPHINX_BUILD_VERSION}) "
"and sphinx-quickstart (${SPHINX_QUICKSTART_VERSION}) "
"do not match")
endif()
endif()
find_package_handle_standard_args(
Sphinx
VERSION_VAR SPHINX_BUILD_VERSION
REQUIRED_VARS SPHINX_BUILD_EXECUTABLE SPHINX_BUILD_VERSION
HANDLE_COMPONENTS)
# Generate a conf.py template file using sphinx-quickstart.
#
# sphinx-quickstart allows for quiet operation and a lot of settings can be
# specified as command line arguments, therefore its not required to parse the
# generated conf.py.
function(_Sphinx_generate_confpy _target _cachedir)
if(NOT TARGET Sphinx::quickstart)
message(FATAL_ERROR "sphinx-quickstart is not available, needed by"
"sphinx_add_docs for target ${_target}")
endif()
if(NOT DEFINED SPHINX_PROJECT)
set(SPHINX_PROJECT ${PROJECT_NAME})
endif()
if(NOT DEFINED SPHINX_AUTHOR)
set(SPHINX_AUTHOR "${SPHINX_PROJECT} committers")
endif()
if(NOT DEFINED SPHINX_COPYRIGHT)
string(TIMESTAMP "%Y, ${SPHINX_AUTHOR}" SPHINX_COPYRIGHT)
endif()
if(NOT DEFINED SPHINX_VERSION)
set(SPHINX_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
endif()
if(NOT DEFINED SPHINX_RELEASE)
set(SPHINX_RELEASE "${PROJECT_VERSION}")
endif()
if(NOT DEFINED SPHINX_LANGUAGE)
set(SPHINX_LANGUAGE "en")
endif()
if(NOT DEFINED SPHINX_MASTER)
set(SPHINX_MASTER "index")
endif()
set(_known_exts autodoc doctest intersphinx todo coverage imgmath mathjax
ifconfig viewcode githubpages)
if(DEFINED SPHINX_EXTENSIONS)
foreach(_ext ${SPHINX_EXTENSIONS})
set(_is_known_ext FALSE)
foreach(_known_ext ${_known_exsts})
if(_ext STREQUAL _known_ext)
set(_opts "${opts} --ext-${_ext}")
set(_is_known_ext TRUE)
break()
endif()
endforeach()
if(NOT _is_known_ext)
if(_exts)
set(_exts "${_exts},${_ext}")
else()
set(_exts "${_ext}")
endif()
endif()
endforeach()
endif()
if(_exts)
set(_exts "--extensions=${_exts}")
endif()
set(_templatedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.template")
file(MAKE_DIRECTORY "${_templatedir}")
string(REPLACE " " ";" _Sphinx_executable ${SPHINX_QUICKSTART_EXECUTABLE})
execute_process(
COMMAND ${_Sphinx_executable}
-q --no-makefile --no-batchfile
-p "${SPHINX_PROJECT}"
-a "${SPHINX_AUTHOR}"
-v "${SPHINX_VERSION}"
-r "${SPHINX_RELEASE}"
-l "${SPHINX_LANGUAGE}"
--master "${SPHINX_MASTER}"
${_opts} ${_exts} "${_templatedir}"
RESULT_VARIABLE _result
OUTPUT_QUIET)
unset(_Sphinx_executable)
if(_result EQUAL 0 AND EXISTS "${_templatedir}/conf.py")
file(COPY "${_templatedir}/conf.py" DESTINATION "${_cachedir}")
endif()
file(REMOVE_RECURSE "${_templatedir}")
if(NOT _result EQUAL 0 OR NOT EXISTS "${_cachedir}/conf.py")
message(FATAL_ERROR "Sphinx configuration file not generated for "
"target ${_target}")
endif()
endfunction()
function(sphinx_add_docs _target)
set(_opts)
set(_single_opts BUILDER OUTPUT_DIRECTORY SOURCE_DIRECTORY)
set(_multi_opts BREATHE_PROJECTS)
cmake_parse_arguments(_args "${_opts}" "${_single_opts}" "${_multi_opts}" ${ARGN})
unset(SPHINX_BREATHE_PROJECTS)
if(NOT _args_BUILDER)
message(FATAL_ERROR "Sphinx builder not specified for target ${_target}")
elseif(NOT _args_SOURCE_DIRECTORY)
message(FATAL_ERROR "Sphinx source directory not specified for target ${_target}")
else()
if(NOT IS_ABSOLUTE "${_args_SOURCE_DIRECTORY}")
get_filename_component(_sourcedir "${_args_SOURCE_DIRECTORY}" ABSOLUTE)
else()
set(_sourcedir "${_args_SOURCE_DIRECTORY}")
endif()
if(NOT IS_DIRECTORY "${_sourcedir}")
message(FATAL_ERROR "Sphinx source directory '${_sourcedir}' for"
"target ${_target} does not exist")
endif()
endif()
set(_builder "${_args_BUILDER}")
if(_args_OUTPUT_DIRECTORY)
set(_outputdir "${_args_OUTPUT_DIRECTORY}")
else()
set(_outputdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}")
endif()
if(_args_BREATHE_PROJECTS)
if(NOT Sphinx_breathe_FOUND)
message(FATAL_ERROR "Sphinx extension 'breathe' is not available. Needed"
"by sphinx_add_docs for target ${_target}")
endif()
list(APPEND SPHINX_EXTENSIONS breathe)
foreach(_doxygen_target ${_args_BREATHE_PROJECTS})
if(TARGET ${_doxygen_target})
list(APPEND _depends ${_doxygen_target})
# Doxygen targets are supported. Verify that a Doxyfile exists.
get_target_property(_dir ${_doxygen_target} BINARY_DIR)
set(_doxyfile "${_dir}/Doxyfile.${_doxygen_target}")
if(NOT EXISTS "${_doxyfile}")
message(FATAL_ERROR "Target ${_doxygen_target} is not a Doxygen"
"target, needed by sphinx_add_docs for target"
"${_target}")
endif()
# Read the Doxyfile, verify XML generation is enabled and retrieve the
# output directory.
file(READ "${_doxyfile}" _contents)
if(NOT _contents MATCHES "GENERATE_XML *= *YES")
message(FATAL_ERROR "Doxygen target ${_doxygen_target} does not"
"generate XML, needed by sphinx_add_docs for"
"target ${_target}")
elseif(_contents MATCHES "OUTPUT_DIRECTORY *= *([^ ][^\n]*)")
string(STRIP "${CMAKE_MATCH_1}" _dir)
set(_name "${_doxygen_target}")
set(_dir "${_dir}/xml")
else()
message(FATAL_ERROR "Cannot parse Doxyfile generated by Doxygen"
"target ${_doxygen_target}, needed by"
"sphinx_add_docs for target ${_target}")
endif()
elseif(_doxygen_target MATCHES "([^: ]+) *: *(.*)")
set(_name "${CMAKE_MATCH_1}")
string(STRIP "${CMAKE_MATCH_2}" _dir)
endif()
if(_name AND _dir)
if(_breathe_projects)
set(_breathe_projects "${_breathe_projects}, \"${_name}\": \"${_dir}\"")
else()
set(_breathe_projects "\"${_name}\": \"${_dir}\"")
endif()
if(NOT _breathe_default_project)
set(_breathe_default_project "${_name}")
endif()
endif()
endforeach()
endif()
set(_cachedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache")
file(MAKE_DIRECTORY "${_cachedir}")
if(EXISTS "${_sourcedir}/_static")
file(COPY "${_sourcedir}/_static" DESTINATION "${_cachedir}")
endif()
if(EXISTS "${_sourcedir}/_templates")
file(COPY "${_sourcedir}/_templates" DESTINATION "${_cachedir}")
endif()
if(EXISTS "${_sourcedir}/conf.py")
configure_file("${_sourcedir}/conf.py" "${_cachedir}/conf.py" @ONLY)
else()
_Sphinx_generate_confpy(${_target} "${_cachedir}")
endif()
if(_breathe_projects)
file(APPEND "${_cachedir}/conf.py"
"\nbreathe_projects = { ${_breathe_projects} }"
"\nbreathe_default_project = '${_breathe_default_project}'")
endif()
string(REPLACE " " ";" _Sphinx_executable ${SPHINX_BUILD_EXECUTABLE})
add_custom_target(
${_target} ALL
COMMAND ${_Sphinx_executable}
-b ${_builder}
-d "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache/_doctrees"
-c "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache"
"${_sourcedir}"
"${_outputdir}"
COMMENT "Building ${_target} Sphinx document"
DEPENDS ${_depends})
unset(_Sphinx_executable)
endfunction()

@ -13,6 +13,17 @@
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
find_package(Doxygen REQUIRED) find_package(Doxygen REQUIRED)
#-----------------------------------------------------------------------------
# Function to turn CMake booleans to `YES` or `NO` as expected by Doxygen
#-----------------------------------------------------------------------------
function(to_yes_no variable)
if(${variable})
set(${variable} YES PARENT_SCOPE)
else()
set(${variable} NO PARENT_SCOPE)
endif()
endfunction()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Configure Doxygen # Configure Doxygen
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@ -20,6 +31,9 @@ set(VTKm_DOXYGEN_HAVE_DOT ${DOXYGEN_DOT_FOUND})
set(VTKm_DOXYGEN_DOT_PATH ${DOXYGEN_DOT_PATH}) set(VTKm_DOXYGEN_DOT_PATH ${DOXYGEN_DOT_PATH})
set(VTKm_DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/docs/doxyfile) set(VTKm_DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/docs/doxyfile)
to_yes_no(VTKm_ENABLE_USERS_GUIDE)
to_yes_no(VTKm_Doxygen_HTML_output)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMake/doxyfile.in ${VTKm_DOXYFILE} configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMake/doxyfile.in ${VTKm_DOXYFILE}
@ONLY) @ONLY)

@ -36,6 +36,7 @@ set(FILES_TO_CHECK
set(EXCEPTIONS set(EXCEPTIONS
LICENSE.txt LICENSE.txt
README.txt README.txt
docs/users-guide/requirements.txt
) )
if (NOT VTKm_SOURCE_DIR) if (NOT VTKm_SOURCE_DIR)

@ -72,6 +72,7 @@ set(VTKm_ENABLE_OPENMP "@VTKm_ENABLE_OPENMP@")
set(VTKm_ENABLE_TBB "@VTKm_ENABLE_TBB@") set(VTKm_ENABLE_TBB "@VTKm_ENABLE_TBB@")
set(VTKm_ENABLE_LOGGING "@VTKm_ENABLE_LOGGING@") set(VTKm_ENABLE_LOGGING "@VTKm_ENABLE_LOGGING@")
set(VTKm_ENABLE_RENDERING "@VTKm_ENABLE_RENDERING@") set(VTKm_ENABLE_RENDERING "@VTKm_ENABLE_RENDERING@")
set(VTKm_ENABLE_ANARI "@VTKm_ENABLE_ANARI@")
set(VTKm_ENABLE_GL_CONTEXT "@VTKm_ENABLE_GL_CONTEXT@") set(VTKm_ENABLE_GL_CONTEXT "@VTKm_ENABLE_GL_CONTEXT@")
set(VTKm_ENABLE_OSMESA_CONTEXT "@VTKm_ENABLE_OSMESA_CONTEXT@") set(VTKm_ENABLE_OSMESA_CONTEXT "@VTKm_ENABLE_OSMESA_CONTEXT@")
set(VTKm_ENABLE_EGL_CONTEXT "@VTKm_ENABLE_EGL_CONTEXT@") set(VTKm_ENABLE_EGL_CONTEXT "@VTKm_ENABLE_EGL_CONTEXT@")
@ -93,6 +94,7 @@ endif()
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
set(CMAKE_MODULE_PATH_save_vtkm "${CMAKE_MODULE_PATH}") set(CMAKE_MODULE_PATH_save_vtkm "${CMAKE_MODULE_PATH}")
set(PACKAGE_PREFIX_DIR_save_vtkm "${PACKAGE_PREFIX_DIR}")
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}")
if (VTKm_ENABLE_TBB) if (VTKm_ENABLE_TBB)
@ -103,6 +105,16 @@ if (VTKm_ENABLE_TBB)
endif() endif()
endif() endif()
if (VTKm_ENABLE_ANARI)
find_dependency(anari)
if (NOT anari_FOUND)
set(VTKm_FOUND 0)
list(APPEND VTKm_NOT_FOUND_REASON "ANARI not found: ${anari_NOT_FOUND_MESSAGE}")
endif()
endif()
set(PACKAGE_PREFIX_DIR ${PACKAGE_PREFIX_DIR_save_vtkm})
# Load the library exports, but only if not compiling VTK-m itself # Load the library exports, but only if not compiling VTK-m itself
set_and_check(VTKm_CONFIG_DIR "@PACKAGE_VTKm_INSTALL_CONFIG_DIR@") set_and_check(VTKm_CONFIG_DIR "@PACKAGE_VTKm_INSTALL_CONFIG_DIR@")
set(VTKM_FROM_INSTALL_DIR FALSE) set(VTKM_FROM_INSTALL_DIR FALSE)

@ -350,6 +350,7 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm_kokkos)
elseif(HIP IN_LIST Kokkos_DEVICES) elseif(HIP IN_LIST Kokkos_DEVICES)
cmake_minimum_required(VERSION 3.18 FATAL_ERROR) cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
enable_language(HIP) enable_language(HIP)
set_target_properties(Kokkos::kokkoscore PROPERTIES set_target_properties(Kokkos::kokkoscore PROPERTIES
INTERFACE_COMPILE_OPTIONS "" INTERFACE_COMPILE_OPTIONS ""
INTERFACE_LINK_OPTIONS "" INTERFACE_LINK_OPTIONS ""
@ -357,14 +358,6 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm_kokkos)
add_library(vtkm_kokkos_hip INTERFACE) add_library(vtkm_kokkos_hip INTERFACE)
set_property(TARGET vtkm_kokkos_hip PROPERTY EXPORT_NAME kokkos_hip) set_property(TARGET vtkm_kokkos_hip PROPERTY EXPORT_NAME kokkos_hip)
install(TARGETS vtkm_kokkos_hip EXPORT ${VTKm_EXPORT_NAME}) install(TARGETS vtkm_kokkos_hip EXPORT ${VTKm_EXPORT_NAME})
# Make sure rocthrust is available if requested
if(VTKm_ENABLE_KOKKOS_THRUST)
find_package(rocthrust)
if(NOT rocthrust_FOUND)
message(FATAL_ERROR "rocthrust not found. Please set VTKm_ENABLE_KOKKOS_THRUST to OFF.")
endif()
endif()
endif() endif()
add_library(vtkm_kokkos INTERFACE IMPORTED GLOBAL) add_library(vtkm_kokkos INTERFACE IMPORTED GLOBAL)

@ -10,7 +10,11 @@
#ifndef @EXPORT_MACRO_NAME@_EXPORT_H #ifndef @EXPORT_MACRO_NAME@_EXPORT_H
#define @EXPORT_MACRO_NAME@_EXPORT_H #define @EXPORT_MACRO_NAME@_EXPORT_H
#if defined(_MSC_VER) #if defined(VTKM_DOXYGEN_ONLY)
# define @EXPORT_MACRO_NAME@_EXPORT_DEFINE
# define @EXPORT_MACRO_NAME@_IMPORT_DEFINE
# define @EXPORT_MACRO_NAME@_NO_EXPORT_DEFINE
#elif defined(_MSC_VER)
# if @EXPORT_IS_BUILT_STATIC@ # if @EXPORT_IS_BUILT_STATIC@
/* This is a static component and has no need for exports /* This is a static component and has no need for exports
elf based static libraries are able to have hidden/default visibility elf based static libraries are able to have hidden/default visibility

@ -221,7 +221,7 @@ function(_vtkm_module_parse_module_file module_file name_var)
# Parse module file as arguments to a function # Parse module file as arguments to a function
set(options NO_TESTING) set(options NO_TESTING)
set(oneValueArgs NAME) set(oneValueArgs NAME TESTING_DIR)
set(multiValueArgs set(multiValueArgs
GROUPS DEPENDS PRIVATE_DEPENDS OPTIONAL_DEPENDS TEST_DEPENDS TEST_OPTIONAL_DEPENDS) GROUPS DEPENDS PRIVATE_DEPENDS OPTIONAL_DEPENDS TEST_DEPENDS TEST_OPTIONAL_DEPENDS)
cmake_parse_arguments(_vtkm_module cmake_parse_arguments(_vtkm_module
@ -562,6 +562,26 @@ so that other modules know this module is loaded.")
get_property(_vtkm_module_list GLOBAL PROPERTY "_vtkm_module_list") get_property(_vtkm_module_list GLOBAL PROPERTY "_vtkm_module_list")
list(APPEND _vtkm_module_list ${target_module}) list(APPEND _vtkm_module_list ${target_module})
set_property(GLOBAL PROPERTY "_vtkm_module_list" "${_vtkm_module_list}") set_property(GLOBAL PROPERTY "_vtkm_module_list" "${_vtkm_module_list}")
get_property(target_module_type
TARGET "${target_module}"
PROPERTY TYPE)
if (target_module_type STREQUAL "SHARED_LIBRARY")
set_property(TARGET "${target_module}"
PROPERTY
BUILD_RPATH_USE_ORIGIN 1)
if (UNIX)
if (APPLE)
set(target_module_rpath
"@loader_path")
else ()
set(target_module_rpath
"$ORIGIN")
endif ()
set_property(TARGET "${target_module}" APPEND
PROPERTY
INSTALL_RPATH "${target_module_rpath}")
endif ()
endif()
endfunction() endfunction()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -592,10 +612,16 @@ function(_vtkm_modules_try_build_tests target_module)
endif() endif()
endforeach() endforeach()
vtkm_module_get_property(testing_subdir ${target_module} TESTING_DIR)
if(NOT testing_subdir)
set(testing_subdir "testing")
endif()
vtkm_module_get_property(src_directory ${target_module} DIRECTORY) vtkm_module_get_property(src_directory ${target_module} DIRECTORY)
file(RELATIVE_PATH rel_directory "${VTKm_SOURCE_DIR}" "${src_directory}") file(RELATIVE_PATH rel_directory "${VTKm_SOURCE_DIR}" "${src_directory}")
set(vtkm_module_current_test ${target_module}) set(vtkm_module_current_test ${target_module})
add_subdirectory("${src_directory}/testing" "${VTKm_BINARY_DIR}/${rel_directory}/testing") add_subdirectory("${src_directory}/${testing_subdir}"
"${VTKm_BINARY_DIR}/${rel_directory}/${testing_subdir}")
set(vtkm_module_current_test) set(vtkm_module_current_test)
endfunction() endfunction()

@ -132,6 +132,7 @@ INPUT = @VTKm_SOURCE_DIR@/README.md
INPUT += @VTKm_SOURCE_DIR@/CONTRIBUTING.md INPUT += @VTKm_SOURCE_DIR@/CONTRIBUTING.md
INPUT += @VTKm_SOURCE_DIR@/docs/CodingConventions.md INPUT += @VTKm_SOURCE_DIR@/docs/CodingConventions.md
INPUT += @VTKm_SOURCE_DIR@/vtkm INPUT += @VTKm_SOURCE_DIR@/vtkm
INPUT += @VTKm_BINARY_DIR@/include
USE_MDFILE_AS_MAINPAGE = README.md USE_MDFILE_AS_MAINPAGE = README.md
@ -148,8 +149,22 @@ EXCLUDE_PATTERNS = */benchmarking/*
EXCLUDE_PATTERNS += */examples/* EXCLUDE_PATTERNS += */examples/*
EXCLUDE_PATTERNS += */testing/* EXCLUDE_PATTERNS += */testing/*
EXCLUDE_PATTERNS += */thirdparty/* EXCLUDE_PATTERNS += */thirdparty/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/filter/*/worklet/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/rendering/raytracing/*
EXCLUDE_PATTERNS += UnitTest* EXCLUDE_PATTERNS += UnitTest*
# Before filters existed in VTK-m, users were expected to interact directly
# with worklets, and several algorithms were written in this way. There are
# some complex algorithms that never made the jump to filters, but we never
# threw them out in hopes they become useful. At some point, we should
# probably delete or remove them, but for now just hide them to keep the
# documentation from getting messy.
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/worklet/colorconversion/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/worklet/cosmotools/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/worklet/spatialstructure/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/worklet/splatkernels/*
EXCLUDE_PATTERNS += @VTKm_SOURCE_DIR@/vtkm/worklet/wavelets/*
EXCLUDE_SYMBOLS = thrust EXCLUDE_SYMBOLS = thrust
EXCLUDE_SYMBOLS += benchmarking EXCLUDE_SYMBOLS += benchmarking
EXCLUDE_SYMBOLS += detail EXCLUDE_SYMBOLS += detail
@ -202,7 +217,7 @@ IGNORE_PREFIX =
# configuration options related to the HTML output # configuration options related to the HTML output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
GENERATE_HTML = YES GENERATE_HTML = @VTKm_Doxygen_HTML_output@
HTML_OUTPUT = html HTML_OUTPUT = html
@ -294,7 +309,7 @@ MAN_LINKS = NO
# configuration options related to the XML output # configuration options related to the XML output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
GENERATE_XML = NO GENERATE_XML = @VTKm_ENABLE_USERS_GUIDE@
XML_OUTPUT = xml XML_OUTPUT = xml
@ -328,13 +343,16 @@ PERLMOD_MAKEVAR_PREFIX =
ENABLE_PREPROCESSING = YES ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO # Turning macro expansion on is required to work around issue with breathe
# (for Sphinx documentation) parsing function modifiers.
# https://github.com/breathe-doc/breathe/issues/905
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES SEARCH_INCLUDES = YES
INCLUDE_PATH = @VTKm_SOURCE_DIR@ @VTKm_BINARY_DIR@ INCLUDE_PATH = @VTKm_SOURCE_DIR@ @VTKm_BINARY_DIR@/include
INCLUDE_FILE_PATTERNS = INCLUDE_FILE_PATTERNS =

@ -9,7 +9,7 @@
##============================================================================ ##============================================================================
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
function(vtkm_test_install ) function(vtkm_test_install)
if(NOT VTKm_INSTALL_ONLY_LIBRARIES) if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
# Find all modules that are not-compiled. Skip these directories. # Find all modules that are not-compiled. Skip these directories.
set(dir_exceptions) set(dir_exceptions)
@ -89,11 +89,11 @@ set(CMAKE_HIP_COMPILER \"${CMAKE_HIP_COMPILER}\" CACHE FILEPATH \"\")
endfunction() endfunction()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
function(vtkm_test_against_install dir) function(vtkm_test_against_install_cmake dir)
set(name ${dir}) set(name ${dir})
set(install_prefix "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_install") set(install_prefix "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_install")
set(src_dir "${CMAKE_CURRENT_SOURCE_DIR}/${name}/") set(src_dir "${CMAKE_CURRENT_SOURCE_DIR}/${name}/")
set(build_dir "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_build/test_${name}/") set(build_dir "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_build/test_${name}_cmake/")
set(args ) set(args )
if(CMAKE_VERSION VERSION_LESS 3.13) if(CMAKE_VERSION VERSION_LESS 3.13)
@ -134,7 +134,7 @@ function(vtkm_test_against_install dir)
#this information to built the test name to make it clear to the user #this information to built the test name to make it clear to the user
#what a 'passing' test means #what a 'passing' test means
set(retcode 0) set(retcode 0)
set(build_name "${name}_built_against_test_install") set(build_name "${name}_cmake_built_against_test_install")
set(test_label "TEST_INSTALL") set(test_label "TEST_INSTALL")
add_test(NAME ${build_name} add_test(NAME ${build_name}
@ -162,3 +162,72 @@ function(vtkm_test_against_install dir)
set_tests_properties(${build_name} PROPERTIES FIXTURES_REQUIRED vtkm_installed) set_tests_properties(${build_name} PROPERTIES FIXTURES_REQUIRED vtkm_installed)
set_tests_properties(${build_name} PROPERTIES TIMEOUT 600) set_tests_properties(${build_name} PROPERTIES TIMEOUT 600)
endfunction() endfunction()
# -----------------------------------------------------------------------------
function(_test_install_make dir name)
set(build_name "${name}_make_built_against_test_install")
set(build_example_dir "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_build/test_${name}_make/")
set(source_example_dir "${CMAKE_CURRENT_SOURCE_DIR}/${dir}/")
# Create build dir if it doesnt exists
add_test(NAME ${build_name}_setup
COMMAND ${CMAKE_COMMAND} -E make_directory ${build_example_dir})
# Build and invoke its test
add_test(NAME ${build_name}
WORKING_DIRECTORY ${build_example_dir}
COMMAND make -f ${source_example_dir}/Makefile check V=1 VPATH=${source_example_dir})
set_tests_properties(${build_name}_setup PROPERTIES FIXTURES_SETUP "makefile_setup")
set_tests_properties(${build_name} PROPERTIES ENVIRONMENT "${ARGN}")
set_tests_properties(${build_name} PROPERTIES LABELS "TEST_INSTALL")
set_tests_properties(${build_name} PROPERTIES FIXTURES_REQUIRED "vtkm_installed;makefile_setup")
set_tests_properties(${build_name} PROPERTIES TIMEOUT 600)
endfunction()
# -----------------------------------------------------------------------------
function(vtkm_test_against_install_make dir)
# Only add tests if and only if Make is found
if (NOT ${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
# Only these compilers accept the -std=c++XX parameter
if (NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang|Intel")
return()
endif()
find_program(make_found make)
if (NOT make_found)
return()
endif()
endif()
set(env_vars
"CXX=${CMAKE_CXX_COMPILER}"
"CXXFLAGS=$CACHE{CMAKE_CXX_FLAGS} -std=c++${CMAKE_CXX_STANDARD}"
)
set(vtkm_install_dir "${VTKm_BINARY_DIR}/CMakeFiles/_tmp_install")
if (WIN32)
string(REPLACE ";" "\\;" escaped_path "$ENV{PATH}")
list(APPEND env_vars "PATH=$<SHELL_PATH:${vtkm_install_dir}/bin>\\;${escaped_path}")
elseif(APPLE)
list(APPEND env_vars "DYLD_LIBRARY_PATH=${vtkm_install_dir}/lib:$ENV{DYLD_LIBRARY_PATH}")
else()
list(APPEND env_vars "LD_LIBRARY_PATH=${vtkm_install_dir}/lib:$ENV{LD_LIBRARY_PATH}")
endif()
# The plain make test uses the given dir as its test name
_test_install_make(${dir} ${dir}
"VTKM_INSTALL_PREFIX=${vtkm_install_dir}"
"VTKM_CONFIG_MK_PATH=${vtkm_install_dir}/share/vtkm-${VTKm_VERSION_MAJOR}.${VTKm_VERSION_MINOR}/vtkm_config.mk"
${env_vars}
)
# Create pkg-config test if pkg-config is found
find_program(pkgconfig_found pkg-config)
if (pkgconfig_found)
_test_install_make(${dir} "${dir}_pkgconfig"
"PKG_CONFIG_PATH=${vtkm_install_dir}/share/vtkm-${VTKm_VERSION_MAJOR}.${VTKm_VERSION_MINOR}/"
"PKG_CONFIG_TEST_ARGS=--define-variable=prefix=${vtkm_install_dir}"
${env_vars}
)
endif()
endfunction()

@ -172,13 +172,13 @@ function(vtkm_unit_tests)
if(VTKm_ENABLE_TBB AND (enable_all_backends OR NOT per_device_suffix)) 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_command_line_arguments --vtkm-device=tbb)
list(APPEND per_device_suffix "TBB") list(APPEND per_device_suffix "TBB")
list(APPEND per_device_timeout 180) list(APPEND per_device_timeout $<IF:$<CONFIG:Debug>,300,180>)
list(APPEND per_device_serial FALSE) list(APPEND per_device_serial FALSE)
endif() endif()
if(VTKm_ENABLE_OPENMP AND (enable_all_backends OR NOT per_device_suffix)) 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_command_line_arguments --vtkm-device=openmp)
list(APPEND per_device_suffix "OPENMP") list(APPEND per_device_suffix "OPENMP")
list(APPEND per_device_timeout 180) list(APPEND per_device_timeout $<IF:$<CONFIG:Debug>,300,180>)
#We need to have all OpenMP tests run serially as they #We need to have all OpenMP tests run serially as they
#will uses all the system cores, and we will cause a N*N thread #will uses all the system cores, and we will cause a N*N thread
#explosion which causes the tests to run slower than when run #explosion which causes the tests to run slower than when run
@ -189,7 +189,7 @@ function(vtkm_unit_tests)
list(APPEND per_device_command_line_arguments --vtkm-device=serial) list(APPEND per_device_command_line_arguments --vtkm-device=serial)
list(APPEND per_device_suffix "SERIAL") list(APPEND per_device_suffix "SERIAL")
list(APPEND per_device_timeout 180) list(APPEND per_device_timeout 180)
list(APPEND per_device_serial FALSE) list(APPEND per_device_serial $<IF:$<CONFIG:Debug>,300,180>)
endif() endif()
if(NOT enable_all_backends) if(NOT enable_all_backends)
# If not enabling all backends, exactly one backend should have been added. # If not enabling all backends, exactly one backend should have been added.
@ -202,7 +202,7 @@ function(vtkm_unit_tests)
# A specific backend was requested. # A specific backend was requested.
set(per_device_command_line_arguments --vtkm-device=${VTKm_UT_BACKEND}) set(per_device_command_line_arguments --vtkm-device=${VTKm_UT_BACKEND})
set(per_device_suffix ${VTKm_UT_BACKEND}) set(per_device_suffix ${VTKm_UT_BACKEND})
set(per_device_timeout 180) set(per_device_timeout $<IF:$<CONFIG:Debug>,300,180>)
# Some devices don't like multiple tests run at the same time. # Some devices don't like multiple tests run at the same time.
set(per_device_serial TRUE) set(per_device_serial TRUE)
endif() endif()

@ -112,6 +112,30 @@ cmake_dependent_option(VTKm_ENABLE_TESTING_LIBRARY "Enable VTKm Testing Library"
OFF "NOT VTKm_ENABLE_TESTING;NOT VTKm_ENABLE_BENCHMARKS" ON) OFF "NOT VTKm_ENABLE_TESTING;NOT VTKm_ENABLE_BENCHMARKS" ON)
mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY) mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY)
# The ANARI interop library uses a bit of code in vtkm_rendering, so this option
# currently requires vtkm_rendering to be built. Eventually this dependency
# should go away as vtkm_anari doesn't require applications to use anything from
# vtkm_rendering directly.
cmake_dependent_option(VTKm_ENABLE_ANARI "Enable ANARI interop support"
OFF "VTKm_ENABLE_RENDERING" OFF)
# If you are building Doxygen, you also have the option to build the User's Guide with Sphinx
cmake_dependent_option(VTKm_ENABLE_USERS_GUIDE
"Build User's Guide with Sphinx"
ON
"VTKm_ENABLE_DOCUMENTATION"
OFF
)
# If you are building the User's Guide, you may only need the XML output from Doxygen, which
# is much faster than generating the HTML. Thus, give the option to turn on/off the HTML output.
cmake_dependent_option(VTKm_Doxygen_HTML_output
"Build HTML output"
ON
"VTKm_ENABLE_USERS_GUIDE"
ON
)
mark_as_advanced(VTKm_Doxygen_HTML_output)
# We may want to make finer controls on whether libraries/modules get built. # We may want to make finer controls on whether libraries/modules get built.
# VTK uses the concept of groups for its modules # VTK uses the concept of groups for its modules
vtkm_option(VTKm_BUILD_ALL_LIBRARIES vtkm_option(VTKm_BUILD_ALL_LIBRARIES
@ -216,6 +240,7 @@ vtkm_module_force_group(Testing
DISABLE_VALUE "DONT_WANT" DISABLE_VALUE "DONT_WANT"
) )
vtkm_module_force_group(Benchmarking ENABLE_OPTION VTKm_ENABLE_BENCHMARKS) vtkm_module_force_group(Benchmarking ENABLE_OPTION VTKm_ENABLE_BENCHMARKS)
vtkm_module_force_group(ANARI ENABLE_OPTION VTKm_ENABLE_ANARI)
# The tutorial requires several common filters. This logic might need to # The tutorial requires several common filters. This logic might need to
# become more complicated (or less compliated if we decide to always # become more complicated (or less compliated if we decide to always
@ -237,6 +262,11 @@ include(VTKmWrappers)
cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)"
ON "VTKm_ENABLE_KOKKOS;Kokkos_ENABLE_CUDA OR Kokkos_ENABLE_HIP" OFF) ON "VTKm_ENABLE_KOKKOS;Kokkos_ENABLE_CUDA OR Kokkos_ENABLE_HIP" OFF)
# CUDA already provides thrust
if (VTKm_ENABLE_KOKKOS_THRUST AND TARGET vtkm_kokkos_hip)
find_package(rocthrust REQUIRED CONFIG)
endif()
# Create vtkm_compiler_flags library. This is an interface library that # Create vtkm_compiler_flags library. This is an interface library that
# holds all the C++ compiler flags that are needed for consumers and # holds all the C++ compiler flags that are needed for consumers and
# when building VTK-m. # when building VTK-m.
@ -298,28 +328,6 @@ include(CheckTypeSize)
check_type_size(long VTKm_SIZE_LONG BUILTIN_TYPES_ONLY) check_type_size(long VTKm_SIZE_LONG BUILTIN_TYPES_ONLY)
check_type_size("long long" VTKm_SIZE_LONG_LONG BUILTIN_TYPES_ONLY) check_type_size("long long" VTKm_SIZE_LONG_LONG BUILTIN_TYPES_ONLY)
#-----------------------------------------------------------------------------
# Add subdirectories
add_subdirectory(vtkmstd)
#-----------------------------------------------------------------------------
# Process modules
vtkm_modules_scan(
SCAN_DIRECTORIES vtkm benchmarking
PROVIDED_MODULES all_modules
)
vtkm_modules_build(
PROVIDED_MODULES ${all_modules}
WANT_BY_DEFAULT ${VTKm_BUILD_ALL_LIBRARIES}
WANT_BY_DEFAULT_REASON "VTKm_BUILD_ALL_LIBRARIES is `${VTKm_BUILD_ALL_LIBRARIES}`"
)
#-----------------------------------------------------------------------------
# Build documentation
if (VTKm_ENABLE_DOCUMENTATION)
include(VTKmBuildDocumentation)
endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Ready files for find_package # Ready files for find_package
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
@ -341,6 +349,28 @@ write_basic_package_version_file(
VERSION ${VTKm_VERSION} VERSION ${VTKm_VERSION}
COMPATIBILITY ExactVersion ) COMPATIBILITY ExactVersion )
#-----------------------------------------------------------------------------
# Add subdirectories
add_subdirectory(vtkmstd)
#-----------------------------------------------------------------------------
# Process modules
vtkm_modules_scan(
SCAN_DIRECTORIES vtkm benchmarking docs
PROVIDED_MODULES all_modules
)
vtkm_modules_build(
PROVIDED_MODULES ${all_modules}
WANT_BY_DEFAULT ${VTKm_BUILD_ALL_LIBRARIES}
WANT_BY_DEFAULT_REASON "VTKm_BUILD_ALL_LIBRARIES is `${VTKm_BUILD_ALL_LIBRARIES}`"
)
#-----------------------------------------------------------------------------
# Build documentation
if (VTKm_ENABLE_DOCUMENTATION)
include(VTKmBuildDocumentation)
endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Create makefile/package files for projects not using CMake # Create makefile/package files for projects not using CMake

@ -32,7 +32,7 @@ met:
without specific prior written permission. without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
@ -48,6 +48,7 @@ The following files and directories come from third parties. Check the
contents of these for details on the specifics of their respective contents of these for details on the specifics of their respective
licenses. licenses.
- - - - - - - - - - - - - - - - - - - - - - - - do not remove this line - - - - - - - - - - - - - - - - - - - - - - - - do not remove this line
CMake/FindSphinx.cmake
CMake/FindTBB.cmake CMake/FindTBB.cmake
Utilities Utilities
vtkm/cont/tbb/internal/parallel_sort.h vtkm/cont/tbb/internal/parallel_sort.h

@ -196,13 +196,22 @@ def create_container(ci_file_path, *args):
if os.getenv('https_proxy'): if os.getenv('https_proxy'):
gitlab_env = [ 'https_proxy=' + os.getenv('https_proxy') ] + gitlab_env gitlab_env = [ 'https_proxy=' + os.getenv('https_proxy') ] + gitlab_env
def clean_script(script):
if isinstance(script, list):
from itertools import chain
return list(chain(*[clean_script(command) for command in script]))
elif isinstance(script, str):
return [script.strip()]
else:
raise(TypeError('Encountered bad type in script: `{}`'.format(type(script).__name__)))
# The script and before_script could be anywhere! # The script and before_script could be anywhere!
script_search_locations = [ci_state, subset, runner] script_search_locations = [ci_state, subset, runner]
for loc in script_search_locations: for loc in script_search_locations:
if 'before_script' in loc: if 'before_script' in loc:
before_script = [command.strip() for command in loc['before_script']] before_script = clean_script(loc['before_script'])
if 'script' in loc: if 'script' in loc:
script = [command.strip() for command in loc['script']] script = clean_script(loc['script'])
docker_template = string.Template(''' docker_template = string.Template('''
FROM $image FROM $image

@ -36,8 +36,7 @@
#include <vtkm/filter/entity_extraction/ThresholdPoints.h> #include <vtkm/filter/entity_extraction/ThresholdPoints.h>
#include <vtkm/filter/field_conversion/CellAverage.h> #include <vtkm/filter/field_conversion/CellAverage.h>
#include <vtkm/filter/field_conversion/PointAverage.h> #include <vtkm/filter/field_conversion/PointAverage.h>
#include <vtkm/filter/field_transform/WarpScalar.h> #include <vtkm/filter/field_transform/Warp.h>
#include <vtkm/filter/field_transform/WarpVector.h>
#include <vtkm/filter/geometry_refinement/Tetrahedralize.h> #include <vtkm/filter/geometry_refinement/Tetrahedralize.h>
#include <vtkm/filter/geometry_refinement/Triangulate.h> #include <vtkm/filter/geometry_refinement/Triangulate.h>
#include <vtkm/filter/geometry_refinement/VertexClustering.h> #include <vtkm/filter/geometry_refinement/VertexClustering.h>
@ -358,10 +357,11 @@ void BenchWarpScalar(::benchmark::State& state)
const vtkm::cont::DeviceAdapterId device = Config.Device; const vtkm::cont::DeviceAdapterId device = Config.Device;
const bool isPartitioned = static_cast<bool>(state.range(0)); const bool isPartitioned = static_cast<bool>(state.range(0));
vtkm::filter::field_transform::WarpScalar filter{ 2. }; vtkm::filter::field_transform::Warp filter;
filter.SetScaleFactor(2.0f);
filter.SetUseCoordinateSystemAsField(true); filter.SetUseCoordinateSystemAsField(true);
filter.SetNormalField(PointVectorsName, vtkm::cont::Field::Association::Points); filter.SetDirectionField(PointVectorsName);
filter.SetScalarFactorField(PointScalarsName, vtkm::cont::Field::Association::Points); filter.SetScaleField(PointScalarsName);
vtkm::cont::PartitionedDataSet input; vtkm::cont::PartitionedDataSet input;
input = isPartitioned ? GetInputPartitionedData() : GetInputDataSet(); input = isPartitioned ? GetInputPartitionedData() : GetInputDataSet();
@ -385,9 +385,10 @@ void BenchWarpVector(::benchmark::State& state)
const vtkm::cont::DeviceAdapterId device = Config.Device; const vtkm::cont::DeviceAdapterId device = Config.Device;
const bool isPartitioned = static_cast<bool>(state.range(0)); const bool isPartitioned = static_cast<bool>(state.range(0));
vtkm::filter::field_transform::WarpVector filter{ 2. }; vtkm::filter::field_transform::Warp filter;
filter.SetScaleFactor(2.0f);
filter.SetUseCoordinateSystemAsField(true); filter.SetUseCoordinateSystemAsField(true);
filter.SetVectorField(PointVectorsName, vtkm::cont::Field::Association::Points); filter.SetDirectionField(PointVectorsName);
vtkm::cont::PartitionedDataSet input; vtkm::cont::PartitionedDataSet input;
input = isPartitioned ? GetInputPartitionedData() : GetInputDataSet(); input = isPartitioned ? GetInputPartitionedData() : GetInputDataSet();

@ -0,0 +1,446 @@
//============================================================================
// 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 "Benchmarker.h"
#include <vtkm/Particle.h>
#include <vtkm/cont/ArrayHandleRandomUniformReal.h>
#include <vtkm/cont/CellLocatorTwoLevel.h>
#include <vtkm/cont/CellLocatorUniformBins.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/internal/OptionParser.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/filter/clean_grid/CleanGrid.h>
#include <vtkm/filter/geometry_refinement/Triangulate.h>
#include <random>
namespace
{
// Hold configuration state (e.g. active device):
vtkm::cont::InitializeResult Config;
class RandomPointGenerator
{
public:
RandomPointGenerator(const vtkm::Bounds& bounds, const vtkm::UInt32& seed)
: Bounds(bounds)
, Seed(seed)
{
using DistType = std::uniform_real_distribution<vtkm::FloatDefault>;
this->Generator = std::default_random_engine(this->Seed);
this->Distributions.resize(3);
this->Distributions[0] = DistType(this->Bounds.X.Min, this->Bounds.X.Max);
this->Distributions[1] = DistType(this->Bounds.Y.Min, this->Bounds.Y.Max);
this->Distributions[2] = DistType(this->Bounds.Z.Min, this->Bounds.Z.Max);
}
vtkm::Vec3f GetPt()
{
return vtkm::Vec3f(this->Distributions[0](this->Generator),
this->Distributions[1](this->Generator),
this->Distributions[2](this->Generator));
}
private:
vtkm::Bounds Bounds;
std::default_random_engine Generator;
std::vector<std::uniform_real_distribution<vtkm::FloatDefault>> Distributions;
vtkm::UInt32 Seed = 0;
};
class FindCellWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn points, ExecObject locator);
using ExecutionSignature = void(_1, _2);
template <typename LocatorType>
VTKM_EXEC void operator()(const vtkm::Vec3f& point, const LocatorType& locator) const
{
vtkm::Id cellId;
vtkm::Vec3f pcoords;
locator.FindCell(point, cellId, pcoords);
}
};
class IterateFindCellWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn points,
ExecObject locator,
WholeArrayIn dx,
WholeArrayIn dy);
using ExecutionSignature = void(_1, _2, _3, _4);
template <typename LocatorType, typename DeltaArrayType>
VTKM_EXEC void operator()(const vtkm::Vec3f& inPoint,
const LocatorType& locator,
const DeltaArrayType& dx,
const DeltaArrayType& dy) const
{
vtkm::Id cellId;
vtkm::Vec3f pcoords;
vtkm::Vec3f pt = inPoint;
typename LocatorType::LastCell lastCell;
for (vtkm::Id i = 0; i < this->NumIters; i++)
{
if (this->UseLastCell)
locator.FindCell(pt, cellId, pcoords, lastCell);
else
locator.FindCell(pt, cellId, pcoords);
// shift each value to -1, 1, then multiply by len;
pt[0] += (dx.Get(i) * 2 - 1.) * this->LenX;
pt[1] += (dy.Get(i) * 2 - 1.) * this->LenY;
}
}
vtkm::FloatDefault LenX = 0.0025;
vtkm::FloatDefault LenY = 0.0025;
vtkm::Id NumIters;
bool UseLastCell = true;
};
vtkm::cont::DataSet CreateExplicitDataSet2D(vtkm::Id Nx, vtkm::Id Ny)
{
vtkm::Id3 dims(Nx, Ny, 1);
const vtkm::Vec3f origin(0, 0, 0);
vtkm::Vec3f spacing(
1 / static_cast<vtkm::FloatDefault>(Nx - 1), 1 / static_cast<vtkm::FloatDefault>(Ny - 1), 0);
auto ds = vtkm::cont::DataSetBuilderUniform::Create(dims, origin, spacing);
//Turn the grid into an explicit triangle grid.
vtkm::filter::geometry_refinement::Triangulate triangulator;
vtkm::filter::clean_grid::CleanGrid cleanGrid;
auto triDS = cleanGrid.Execute(triangulator.Execute(ds));
//triDS.PrintSummary(std::cout);
//Randomly tweak each vertex.
auto coords =
triDS.GetCoordinateSystem().GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Vec3f>>();
auto coordsPortal = coords.WritePortal();
vtkm::Id nCoords = coordsPortal.GetNumberOfValues();
vtkm::FloatDefault dx = spacing[0] * 0.33, dy = spacing[1] * 0.33;
std::default_random_engine dre;
std::uniform_real_distribution<vtkm::FloatDefault> rangeX(-dx, dy);
std::uniform_real_distribution<vtkm::FloatDefault> rangeY(-dy, dy);
for (vtkm::Id i = 0; i < nCoords; i++)
{
auto pt = coordsPortal.Get(i);
pt[0] += rangeX(dre);
pt[1] += rangeY(dre);
coordsPortal.Set(i, pt);
}
return triDS;
}
vtkm::cont::ArrayHandle<vtkm::Vec3f> CreateRandomPoints(vtkm::Id numPoints,
const vtkm::cont::DataSet& ds,
vtkm::Id seed)
{
RandomPointGenerator rpg(ds.GetCoordinateSystem().GetBounds(), seed);
std::vector<vtkm::Vec3f> pts(numPoints);
for (auto& pt : pts)
pt = rpg.GetPt();
return vtkm::cont::make_ArrayHandle(pts, vtkm::CopyFlag::On);
}
template <typename LocatorType>
void RunLocatorBenchmark(const vtkm::cont::ArrayHandle<vtkm::Vec3f>& points, LocatorType& locator)
{
//Call find cell on each point.
vtkm::cont::Invoker invoker;
invoker(FindCellWorklet{}, points, locator);
}
template <typename LocatorType>
void RunLocatorIterateBenchmark(
const vtkm::cont::ArrayHandle<vtkm::Vec3f>& points,
vtkm::Id numIters,
LocatorType& locator,
const vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>& dx,
const vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>& dy,
bool useLastCell)
{
//Call find cell on each point.
vtkm::cont::Invoker invoker;
IterateFindCellWorklet worklet;
worklet.NumIters = numIters;
worklet.UseLastCell = useLastCell;
invoker(worklet, points, locator, dx, dy);
}
void Bench2DCellLocatorTwoLevel(::benchmark::State& state)
{
vtkm::Id numPoints = static_cast<vtkm::Id>(state.range(0));
vtkm::Id Nx = static_cast<vtkm::Id>(state.range(1));
vtkm::Id Ny = static_cast<vtkm::Id>(state.range(2));
vtkm::FloatDefault L1Param = static_cast<vtkm::FloatDefault>(state.range(3));
vtkm::FloatDefault L2Param = static_cast<vtkm::FloatDefault>(state.range(4));
auto triDS = CreateExplicitDataSet2D(Nx, Ny);
const vtkm::cont::DeviceAdapterId device = Config.Device;
vtkm::cont::Timer timer{ device };
vtkm::cont::CellLocatorTwoLevel locator2L;
locator2L.SetDensityL1(L1Param);
locator2L.SetDensityL2(L2Param);
locator2L.SetCellSet(triDS.GetCellSet());
locator2L.SetCoordinates(triDS.GetCoordinateSystem());
locator2L.Update();
//Random number seed. Modify it during the loop to ensure different random numbers.
vtkm::Id seed = 0;
for (auto _ : state)
{
(void)_;
auto points = CreateRandomPoints(numPoints, triDS, seed++);
timer.Start();
RunLocatorBenchmark(points, locator2L);
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
void Bench2DCellLocatorUniformBins(::benchmark::State& state)
{
vtkm::Id numPoints = static_cast<vtkm::Id>(state.range(0));
vtkm::Id Nx = static_cast<vtkm::Id>(state.range(1));
vtkm::Id Ny = static_cast<vtkm::Id>(state.range(2));
vtkm::Id UGNx = static_cast<vtkm::Id>(state.range(3));
vtkm::Id UGNy = static_cast<vtkm::Id>(state.range(4));
auto triDS = CreateExplicitDataSet2D(Nx, Ny);
const vtkm::cont::DeviceAdapterId device = Config.Device;
vtkm::cont::Timer timer{ device };
vtkm::cont::CellLocatorUniformBins locatorUB;
locatorUB.SetDims({ UGNx, UGNy, 1 });
locatorUB.SetCellSet(triDS.GetCellSet());
locatorUB.SetCoordinates(triDS.GetCoordinateSystem());
locatorUB.Update();
//Random number seed. Modify it during the loop to ensure different random numbers.
vtkm::Id seed = 0;
for (auto _ : state)
{
(void)_;
auto points = CreateRandomPoints(numPoints, triDS, seed++);
timer.Start();
RunLocatorBenchmark(points, locatorUB);
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
void Bench2DCellLocatorTwoLevelIterate(::benchmark::State& state)
{
vtkm::Id numPoints = static_cast<vtkm::Id>(state.range(0));
vtkm::Id numIters = static_cast<vtkm::Id>(state.range(1));
vtkm::Id Nx = static_cast<vtkm::Id>(state.range(2));
vtkm::Id Ny = static_cast<vtkm::Id>(state.range(3));
vtkm::FloatDefault L1Param = static_cast<vtkm::FloatDefault>(state.range(4));
vtkm::FloatDefault L2Param = static_cast<vtkm::FloatDefault>(state.range(5));
bool useLastCell = static_cast<bool>(state.range(6));
auto triDS = CreateExplicitDataSet2D(Nx, Ny);
const vtkm::cont::DeviceAdapterId device = Config.Device;
vtkm::cont::Timer timer{ device };
vtkm::cont::CellLocatorTwoLevel locator2L;
locator2L.SetDensityL1(L1Param);
locator2L.SetDensityL2(L2Param);
locator2L.SetCellSet(triDS.GetCellSet());
locator2L.SetCoordinates(triDS.GetCoordinateSystem());
locator2L.Update();
//Random number seed. Modify it during the loop to ensure different random numbers.
vtkm::Id seed = 0;
for (auto _ : state)
{
(void)_;
auto points = CreateRandomPoints(numPoints, triDS, seed++);
auto dx = vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(numIters, seed++);
auto dy = vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(numIters, seed++);
timer.Start();
RunLocatorIterateBenchmark(points, numIters, locator2L, dx, dy, useLastCell);
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
void Bench2DCellLocatorUniformBinsIterate(::benchmark::State& state)
{
vtkm::Id numPoints = static_cast<vtkm::Id>(state.range(0));
vtkm::Id numIters = static_cast<vtkm::Id>(state.range(1));
vtkm::Id Nx = static_cast<vtkm::Id>(state.range(2));
vtkm::Id Ny = static_cast<vtkm::Id>(state.range(3));
vtkm::Id UGNx = static_cast<vtkm::Id>(state.range(4));
vtkm::Id UGNy = static_cast<vtkm::Id>(state.range(5));
bool useLastCell = static_cast<bool>(state.range(6));
auto triDS = CreateExplicitDataSet2D(Nx, Ny);
const vtkm::cont::DeviceAdapterId device = Config.Device;
vtkm::cont::Timer timer{ device };
vtkm::cont::CellLocatorUniformBins locatorUB;
locatorUB.SetDims({ UGNx, UGNy, 1 });
locatorUB.SetCellSet(triDS.GetCellSet());
locatorUB.SetCoordinates(triDS.GetCoordinateSystem());
locatorUB.Update();
locatorUB.SetCellSet(triDS.GetCellSet());
locatorUB.SetCoordinates(triDS.GetCoordinateSystem());
locatorUB.Update();
//Random number seed. Modify it during the loop to ensure different random numbers.
vtkm::Id seed = 0;
for (auto _ : state)
{
(void)_;
auto points = CreateRandomPoints(numPoints, triDS, seed++);
auto dx = vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(numIters, seed++);
auto dy = vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(numIters, seed++);
timer.Start();
RunLocatorIterateBenchmark(points, numIters, locatorUB, dx, dy, useLastCell);
timer.Stop();
state.SetIterationTime(timer.GetElapsedTime());
}
}
void Bench2DCellLocatorTwoLevelGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "NumPoints", "DSNx", "DSNy", "LocL1Param", "LocL2Param" });
auto numPts = { 5000, 10000 };
auto DSdims = { 100, 1000 };
auto L1Param = { 64 };
auto L2Param = { 1 };
for (auto& DSDimx : DSdims)
for (auto& DSDimy : DSdims)
for (auto& np : numPts)
for (auto& l1p : L1Param)
for (auto& l2p : L2Param)
{
bm->Args({ np, DSDimx, DSDimy, l1p, l2p });
}
}
void Bench2DCellLocatorUniformBinsGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "NumPoints", "DSNx", "DSNy", "LocNx", "LocNy" });
auto numPts = { 5000, 10000 };
auto DSdims = { 100, 1000 };
auto numBins = { 100, 500, 1000 };
for (auto& DSDimx : DSdims)
for (auto& DSDimy : DSdims)
for (auto& np : numPts)
for (auto& nb : numBins)
{
bm->Args({ np, DSDimx, DSDimy, nb, nb });
}
}
void Bench2DCellLocatorTwoLevelIterateGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "NumPoints", "NumIters", "DSNx", "DSNy", "LocL1Param", "LocL2Param", "LastCell" });
auto numPts = { 1000, 5000 };
auto numIters = { 100, 500 };
auto DSdims = { 1000 };
auto L1Param = { 64 };
auto L2Param = { 1 };
auto lastCell = { 0, 1 };
for (auto& DSDimx : DSdims)
for (auto& DSDimy : DSdims)
for (auto& np : numPts)
for (auto& ni : numIters)
for (auto& l1p : L1Param)
for (auto& l2p : L2Param)
for (auto& lc : lastCell)
{
bm->Args({ np, ni, DSDimx, DSDimy, l1p, l2p, lc });
}
}
void Bench2DCellLocatorUniformBinsIterateGenerator(::benchmark::internal::Benchmark* bm)
{
bm->ArgNames({ "NumPoints", "NumIters", "DSNx", "DSNy", "LocNx", "LocNY", "LastCell" });
auto numPts = { 1000, 5000 };
auto numIters = { 100, 500 };
auto DSdims = { 1000 };
auto numBins = { 128 };
auto lastCell = { 0, 1 };
for (auto& DSDimx : DSdims)
for (auto& DSDimy : DSdims)
for (auto& np : numPts)
for (auto& ni : numIters)
for (auto& nb : numBins)
for (auto& lc : lastCell)
{
bm->Args({ np, ni, DSDimx, DSDimy, nb, nb, lc });
}
}
VTKM_BENCHMARK_APPLY(Bench2DCellLocatorTwoLevel, Bench2DCellLocatorTwoLevelGenerator);
VTKM_BENCHMARK_APPLY(Bench2DCellLocatorUniformBins, Bench2DCellLocatorUniformBinsGenerator);
VTKM_BENCHMARK_APPLY(Bench2DCellLocatorTwoLevelIterate, Bench2DCellLocatorTwoLevelIterateGenerator);
VTKM_BENCHMARK_APPLY(Bench2DCellLocatorUniformBinsIterate,
Bench2DCellLocatorUniformBinsIterateGenerator);
} // end anon namespace
int main(int argc, char* argv[])
{
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
std::vector<char*> args(argv, argv + argc);
vtkm::bench::detail::InitializeArgs(&argc, args, opts);
Config = vtkm::cont::Initialize(argc, args.data(), opts);
if (opts != vtkm::cont::InitializeOptions::None)
{
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
}
VTKM_EXECUTE_BENCHMARKS(argc, args.data());
}

@ -33,7 +33,7 @@ void BenchParticleAdvection(::benchmark::State& state)
vtkm::Id numPoints = dims[0] * dims[1] * dims[2]; vtkm::Id numPoints = dims[0] * dims[1] * dims[2];
std::vector<vtkm::Vec3f> vectorField(static_cast<std::size_t>(numPoints)); std::vector<vtkm::Vec3f> vectorField(static_cast<std::size_t>(numPoints)); // 3D
for (std::size_t i = 0; i < static_cast<std::size_t>(numPoints); i++) for (std::size_t i = 0; i < static_cast<std::size_t>(numPoints); i++)
vectorField[i] = vecX; vectorField[i] = vecX;

@ -47,6 +47,7 @@ set(benchmarks
BenchmarkDeviceAdapter BenchmarkDeviceAdapter
BenchmarkFieldAlgorithms BenchmarkFieldAlgorithms
BenchmarkFilters BenchmarkFilters
BenchmarkLocators
BenchmarkODEIntegrators BenchmarkODEIntegrators
BenchmarkTopologyAlgorithms BenchmarkTopologyAlgorithms
) )

@ -17,5 +17,5 @@ libdir=${exec_prefix}/lib
Name: VTKm Name: VTKm
Description: The VTKm library Description: The VTKm library
Version: @VTKm_VERSION@ Version: @VTKm_VERSION@
Cflags: -I${includedir}/vtkm-@CMAKE_INSTALL_PREFIX@ Cflags: -I${includedir} -I${includedir}/vtkm/thirdparty/diy/vtkmdiy/include/ -I${includedir}/vtkm/thirdparty/lcl/vtkmlcl/
Libs: -L${libdir}@lib_args@ Libs: -L${libdir}@lib_args@

@ -24,5 +24,7 @@ VTKm_ENABLE_OSMESA_CONTEXT = @VTKm_ENABLE_OSMESA_CONTEXT@
VTKm_ENABLE_EGL_CONTEXT = @VTKm_ENABLE_EGL_CONTEXT@ VTKm_ENABLE_EGL_CONTEXT = @VTKm_ENABLE_EGL_CONTEXT@
VTKm_ENABLE_MPI = @VTKm_ENABLE_MPI@ VTKm_ENABLE_MPI = @VTKm_ENABLE_MPI@
VTKm_INCLUDE_FLAGS = -I $(VTKm_DIR)/include/vtkm-@VTKm_VERSION_MAJOR@.@VTKm_VERSION_MINOR@ VTKm_INCLUDE_DIR = $(VTKm_DIR)/include/vtkm-@VTKm_VERSION_MAJOR@.@VTKm_VERSION_MINOR@
VTKm_INCLUDE_FLAGS = -I$(VTKm_INCLUDE_DIR) -I$(VTKm_INCLUDE_DIR)/vtkm/thirdparty/diy/vtkmdiy/include/ -I$(VTKm_INCLUDE_DIR)/vtkm/thirdparty/lcl/vtkmlcl/
VTKm_LIB_FLAGS = -L $(VTKm_DIR)/lib@lib_args@ VTKm_LIB_FLAGS = -L $(VTKm_DIR)/lib@lib_args@

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

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

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

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

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

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

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

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

@ -102,7 +102,7 @@ class ExposedClass;
if (test) if (test)
{ {
clause; clause;
} }
``` ```
+ Conditional clauses including loop conditionals such as for and while + Conditional clauses including loop conditionals such as for and while
@ -112,7 +112,7 @@ if (test)
for (auto v : vector) for (auto v : vector)
{ {
single line clause; single line clause;
} }
``` ```
+ Two space indentation. Tabs are not allowed. Trailing whitespace + Two space indentation. Tabs are not allowed. Trailing whitespace
@ -199,8 +199,8 @@ for (auto v : vector)
`vtkm::IdComponent` for indices and sizes. Consider using `vtkm::IdComponent` for indices and sizes. Consider using
`vtkm::FloatDefault` makes sense. Otherwise, use one of VTK-m's types `vtkm::FloatDefault` makes sense. Otherwise, use one of VTK-m's types
do be explicit about the data type. These are `vtkm::Int8`, do be explicit about the data type. These are `vtkm::Int8`,
vtkm::UInt8`, `vtkm::Int16`, vtkm::UInt16`, `vtkm::Int32`, `vtkm::UInt8`, `vtkm::Int16`, `vtkm::UInt16`, `vtkm::Int32`,
vtkm::UInt32`, `vtkm::Float32`, `vtkm::Int64`, vtkm::UInt64`, and `vtkm::UInt32`, `vtkm::Float32`, `vtkm::Int64`, `vtkm::UInt64`, and
`vtkm::Float64`. `vtkm::Float64`.
+ All functions and methods defined within the VTK-m toolkit should be + All functions and methods defined within the VTK-m toolkit should be

@ -102,6 +102,8 @@ arguments for that option. The following options can be defined in a
named `testing`, which will build any necessary testing executables and named `testing`, which will build any necessary testing executables and
add ctest tests. If this option is given, no tests are added. (Note, add ctest tests. If this option is given, no tests are added. (Note,
modules generally should have tests.) modules generally should have tests.)
* `TESTING_DIR`: Specify the name of the testing subdirectory. If not
provided, `testing` is used.
A `vtkm.module` file may also have comments. Everything between a `#` and A `vtkm.module` file may also have comments. Everything between a `#` and
the end of the line will be ignored. the end of the line will be ignored.

@ -109,8 +109,12 @@ $endif\
- [ ] Unfreeze the release branch (In Gitlab VTK-m page) - [ ] Unfreeze the release branch (In Gitlab VTK-m page)
- Settings/Repository/Protected Branches: Release; "allowed to push: Maintainers" - Settings/Repository/Protected Branches: Release; "allowed to push: Maintainers"
## Update Spack ## Update Packages
- [ ] Update Spack package: https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/vtk-m/package.py - [ ] Update Spack package: https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/vtk-m/package.py
- [ ] Update Conda-forge package: https://github.com/conda-forge/vtk-m-feedstock
$if(RC == "")\
- [ ] Update OBS package: https://build.opensuse.org/package/show/science/vtk-m
$endif\
## Post-release ## Post-release
$if(PATCH == 0 and RC == "-rc1")\ $if(PATCH == 0 and RC == "-rc1")\
@ -246,7 +250,7 @@ git log --format="%an" v1.4.0..v1.5.0 | sort -u | wc -l
Example to compute the number of merge requests Example to compute the number of merge requests
``` ```
git log v1.4.0..v1.5.0 | grep 'Merge | wc -l git log v2.0.0..v2.1.0 | grep 'Merge topic' | wc -l
``` ```
A standard template to use is: A standard template to use is:
@ -264,11 +268,9 @@ https://gitlab.kitware.com/vtk/vtk-m/-/tags/v$(VERSION)) or in the vtkm
repository at `docs/$(VERSION)/release-notes.md` repository at `docs/$(VERSION)/release-notes.md`
$if(int(PATCH) > 0)\ $if(int(PATCH) > 0)\
- Update the link to register with the VTK-m dashboard - changelog title 1
. - changelog title 2
. - changelog title 3
.
- CMAKE: CUDA ampere generate sm_80/86
$else\ $else\
1. Core 1. Core
- Core change 1 - Core change 1

@ -6,8 +6,8 @@
| 1.8.0 | 2022-06-01 | +14 | Long Term | 2023-06-01 | | 1.8.0 | 2022-06-01 | +14 | Long Term | 2023-06-01 |
| 1.9.0 | 2022-09-01 | +41 | Short Term | 2023-06-01 | | 1.9.0 | 2022-09-01 | +41 | Short Term | 2023-06-01 |
| 2.0.0 | 2022-12-01 | +52 | Long Term* | 2023-12-01 | | 2.0.0 | 2022-12-01 | +52 | Long Term* | 2023-12-01 |
| 2.1.0 | 2023-06-01 | | Short Term* | TBD | | 2.1.0 | 2023-06-01 | +182 | Short Term* | TBD |
| 2.2.0 | 2023-09-01 | | Long Term* | TBD | | 2.2.0 | 2023-12-31 | | Long Term* | TBD |
## Legend ## Legend

@ -36,6 +36,8 @@
- Implement Flying Edges for structured cellsets with rectilinear and curvilinear coordinates. - Implement Flying Edges for structured cellsets with rectilinear and curvilinear coordinates.
- Added a `HistSampling` filter. - Added a `HistSampling` filter.
- New Shrink filter. - New Shrink filter.
- Fix interpolation of cell fields with flying edges.
- Fix degenerate cell removal.
4. [Control Environment](#Control_Environment) 4. [Control Environment](#Control_Environment)
- Added a reader for VisIt files. - Added a reader for VisIt files.
@ -46,6 +48,7 @@
- Require Kokkos 3.7. - Require Kokkos 3.7.
- Sped up compilation of ArrayRangeCompute.cxx. - Sped up compilation of ArrayRangeCompute.cxx.
- Kokkos atomic functions switched to use desul library. - Kokkos atomic functions switched to use desul library.
- Added Makefile contract tests.
6. [Others](#Others) 6. [Others](#Others)
- Clarified license of test data. - Clarified license of test data.
@ -526,9 +529,26 @@ This filter assumes the field data are point clouds. It samples the field data a
The Shrink filter shrinks the cells of a DataSet towards their centroid, computed as the average position of the cell points. This filter disconnects the cells, duplicating the points connected to multiple cells. The resulting CellSet is always an `ExplicitCellSet`. The Shrink filter shrinks the cells of a DataSet towards their centroid, computed as the average position of the cell points. This filter disconnects the cells, duplicating the points connected to multiple cells. The resulting CellSet is always an `ExplicitCellSet`.
## Fix interpolation of cell fields with flying edges
The flying edges algorithm (used when contouring uniform structured cell
sets) was not interpolating cell fields correctly. There was an indexing
issue where a shortcut in the stepping was not incrementing the cell index.
## Fix degenerate cell removal
There was a bug in `CleanGrid` when removing degenerate polygons where it
would not detect if the first and last point were the same. This has been
fixed.
There was also an error with function overloading that was causing 0D and
3D cells to enter the wrong computation for degenerate cells. This has also
been fixed.
# Control Environment # Control Environment
## Added a reader for VisIt files. ## Added a reader for VisIt files
A VisIt file is a text file that contains the path and filename of a number of VTK files. This provides a convenient way to load `vtkm::cont::PartitionedDataSet` data from VTK files. The first line of the file is the keyword `!NBLOCKS <N>` that specifies the number of VTK files to be read. A VisIt file is a text file that contains the path and filename of a number of VTK files. This provides a convenient way to load `vtkm::cont::PartitionedDataSet` data from VTK files. The first line of the file is the keyword `!NBLOCKS <N>` that specifies the number of VTK files to be read.
@ -586,6 +606,20 @@ Kokkos 4 switches from their interal library based off of desul to using desul
directly. This removes VTK-m's dependency on the Kokkos internal directly. This removes VTK-m's dependency on the Kokkos internal
implementation (Kokkos::Impl) to using desul directly. implementation (Kokkos::Impl) to using desul directly.
## Added Makefile contract tests
Added Makefile contract tests to ensure that the VTK-m smoke test example
application can be built and run using a Makefile against a VTK-m install tree.
This will help users who use bare Make as their build system. Additionally,
fixed both the VTK-m pkg-config `vtkm.pc` and the `vtkm_config.mk` file to
ensure that both files are correctly generated and added CI coverage to ensure
that they are always up-to-date and correct. This improves support for users
who use bare Make as their build system, and increases confidence in the
correctness of both the VTK-m pkg-config file `vtkm.pc` and of the Makefile
`vtkm_config.mk`.
You can run these tests with: `ctest -R smoke_test`
# Others # Others
## Clarified license of test data ## Clarified license of test data

@ -0,0 +1,3 @@
# AtomicArrayExecutionObject: Allow order of atomic operations
AtomicArrayExecutionObject now allows order of atomic operations for Get/Set/Add/CompareExchange.

@ -0,0 +1,3 @@
# Adding MergeDataSets filter
The MergeDataSets filter can accept partitioned data sets and output a merged data set. It assumes that all partitions have the same coordinate systems. If a field is missing in a specific partition, the user-specified invalid value will be adopted and filled into the corresponding places of the merged field array.

@ -0,0 +1,3 @@
# Adding SliceMultiple filter
The SliceMultiple filter can accept multiple implicit functions and output a merged dataset. This filter is added to the filter/contour. The code of this filter is adapted from vtk-h. The mechanism that merges multiple datasets in this filter is supposed to support more general datasets and work a separate filter in the future.

@ -0,0 +1,20 @@
# Add `GetNumberOfComponentsFlat` method to `ArrayHandle`
Getting the number of components (or the number of flattened components)
from an `ArrayHandle` is usually trivial. However, if the `ArrayHandle` is
special in that the number of components is specified at runtime, then it
becomes much more difficult to determine.
Getting the number of components is most important when extracting
component arrays (or reconstructions using component arrays) with
`UnknownArrayHandle`. Previously, `UnknownArrayHandle` used a hack to get
the number of components, which mostly worked but broke down when wrapping
a runtime array inside another array such as `ArrayHandleView`.
To prevent this issue, the ability to get the number of components has been
added to `ArrayHandle` proper. All `Storage` objects for `ArrayHandle`s now
need a method named `GetNumberOfComponentsFlat`. The implementation of this
method is usually trivial. The `ArrayHandle` template now also provides a
`GetNumberOfComponentsFlat` method that gets this information from the
`Storage`. This provides an easy access point for the `UnknownArrayHandle`
to pull this information.

@ -0,0 +1,10 @@
# Avoid floating point exceptions in rendering code
There were some places in the rendering code where floating point
exceptions (FPE) could happen under certain circumstances. Often we do not
care about invalid floating point operation in rendering as they often
occur in degenerate cases that don't contribute anyway. However,
simulations that might include VTK-m might turn on FPE to check their own
operations. In such cases, we don't want errant rendering arithmetic
causing an exception and bringing down the whole code. Thus, we turn on FPE
in some of our test platforms and avoid such operations in general.

@ -0,0 +1,8 @@
# Store constant AMR arrays with less memory
The `AmrArrays` filter generates some cell fields that specify information
about the hierarchy, which are constant across all cells in a partition.
These were previously stored as an array with the same value throughout.
Now, the field is stored as an `ArrayHandleConstant`, which does not
require any real storage. Recent changes to VTK-m allow code to extract the
array as a component efficiently without knowing the storage type.

@ -0,0 +1,17 @@
# Allow floating-point isovalues for contours of integer fields
The flying edges version of the contouring filter converted the isovalues
provided into the same type as the field. This is fine for a floating point
field, but for an integer field the isovalue was truncated to the nearest
integer.
This is problematic because it is common to provide a fractional isovalue
(usually N + 0.5) for integer fields to avoid degenerate cases of the
contour intersecting vertices. It also means the behavior changes between
an integer type that is directly supported (like a `signed char`) or an
integer type that is not directly supported and converted to a floating
point field (like potentially a `char`).
This change updates the worklets to allow the isovalue to have a different
type than the field and to always use a floating point type for the
isovalue.

@ -0,0 +1,22 @@
# Deprecated `vtkm::filter::FilterField`
The original design of the filter base class required several specialized
base classes to control what information was pulled from the input
`DataSet` and provided to the derived class. Since the filter base class was
redesigned, the derived classes all get a `DataSet` and pull their own
information from it. Thus, most specialized filter base classes became
unnecessary and removed.
The one substantial exception was the `FilterField`. This filter base class
managed input and output arrays. This was kept separate from the base
`Filter` because not all filters need the ability to select this
information.
That said, this separation has not been particularly helpful. There are
several other features of `Filter` that does not apply to all subclasses.
Furthermore, there are several derived filters that are using `FilterField`
merely to pick a single part, like selecting a coordinate system, and
ignoring the rest of the abilities.
Thus, it makes more sense to deprecate `FilterField` and have these classes
inherit directly from `Filter`.

@ -0,0 +1,12 @@
# Deprecate the GetCounts() method in Keys objects
The `vtkm::worklet::Keys` object held a `SortedValuesMap` array, an
`Offsets` array, a `Counts` array, and (optionally) a `UniqueKeys` array.
Of these, the `Counts` array is redundant because the counts are trivially
computed by subtracting adjacent entries in the offsets array. This pattern
shows up a lot in VTK-m, and most places we have moved to removing the
counts and just using the offsets.
This change removes the `Count` array from the `Keys` object. Where the
count is needed internally, adjacent offsets are subtracted. The deprecated
`GetCounts` method is implemented by copying values into a new array.

@ -0,0 +1,22 @@
# Support `Fill` for `ArrayHandleStride`
Previously, if you called `Fill` on an `ArrayHandleStride`, you would get
an exception that said the feature was not supported. It turns out that
filling values is very useful in situations where, for example, you need to
initialize an array when processing an unknown type (and thus dealing with
extracted components).
This implementation of `Fill` first attempts to call `Fill` on the
contained array. This only works if the stride is set to 1. If this does
not work, then the code leverages the precompiled `ArrayCopy`. It does this
by first creating a new `ArrayHandleStride` containing the fill value and a
modulo of 1 so that value is constantly repeated. It then reconstructs an
`ArrayHandleStride` for itself with a modified size and offset to match the
start and end indices.
Referencing the `ArrayCopy` was tricky because it kept creating circular
dependencies among `ArrayHandleStride`, `ArrayExtractComponent`, and
`UnknownArrayHandle`. These dependencies were broken by having
`ArrayHandleStride` directly use the internal `ArrayCopyUnknown` function
and to use a forward declaration of `UnknownArrayHandle` rather than
including its header.

32
docs/changelog/hints.md Normal file

@ -0,0 +1,32 @@
# Add hints to device adapter scheduler
The `DeviceAdapter` provides an abstract interface to the accelerator
devices worklets and other algorithms run on. As such, the programmer has
less control about how the device launches each worklet. Each device
adapter has its own configuration parameters and other ways to attempt to
optimize how things are run, but these are always a universal set of
options that are applied to everything run on the device. There is no way
to specify launch parameters for a particular worklet.
To provide this information, VTK-m now supports `Hint`s to the device
adapter. The `DeviceAdapterAlgorithm::Schedule` method takes a templated
argument that is of the type `HintList`. This object contains a template
list of `Hint` types that provide suggestions on how to launch the parallel
execution. The device adapter will pick out hints that pertain to it and
adjust its launching accordingly.
These are called hints rather than, say, directives, because they don't
force the device adapter to do anything. The device adapter is free to
ignore any (and all) hints. The point is that the device adapter can take
into account the information to try to optimize for itself.
A provided hint can be tied to specific device adapters. In this way, an
worklet can further optimize itself. If multiple hints match a device
adapter, the last one in the list will be selected.
The `Worklet` base now has an internal type named `Hints` that points to a
`HintList` that is applied when the worklet is scheduled. Derived worklet
classes can provide hints by simply defining their own `Hints` type.
This feature is experimental and consequently hidden in an `internal`
namespace.

@ -0,0 +1,17 @@
# Fix issue with union placeholder on Intel compiler
We have run into an issue with some Intel compilers where if a `union`
contains a `struct` that has some padding for byte alignment, the value
copy might skip over that padding even when the `union` contains a different
type where those bytes are valid. This breaks the value copy of our
`Variant` class.
This is not a unique problem. We have seen the same thing in other
compilers and already have a workaround for when this happens. The
workaround creates a special struct that has no padding placed at the front
of the `union`. The Intel compiler adds a fun twist in that this
placeholder structure only works if the alignment is at least as high as
the struct that follows it.
To get around this problem, make the alignment of the placeholder `struct`
at large as possible for the size of the `union`.

@ -0,0 +1,7 @@
# New Isosurface Uncertainty Visualization Analysis filter
This new filter, designed for uncertainty analysis of the marching cubes algorithm for isosurface visualization, computes three uncertainty metrics, namely, level-crossing probability, topology case count, and entropy-based uncertainty. This filter requires a 3D cell-structured dataset with ensemble minimum and ensemble maximum values denoting uncertain data range at each grid vertex.
This uncertainty analysis filter analyzes the uncertainty in the marching cubes topology cases. The output dataset consists of 3D point fields corresponding to the level-crossing probability, topology case count, and entropy-based uncertainty.
This VTK-m implementation is based on the algorithm presented in the paper "FunMC2: A Filter for Uncertainty Visualization of Marching Cubes on Multi-Core Devices" by Wang, Z., Athawale, T. M., Moreland, K., Chen, J., Johnson, C. R., & Pugmire, D.

@ -0,0 +1,10 @@
# Constructors for mesh info classes updated to conform with other filters
The `CellMeasures` and `MeshQuality` filters had constructors that took the
metric that the filter should generate. However, this is different than the
iterface of the rest of the filters. To make the interface more consistent,
these filters now have a default (no argument) constructor, and the metric
to compute is selected via a method. This makes it more clear what is being
done.
In addition, the documentation for these two classes is updated.

@ -0,0 +1,16 @@
# Enable new instances of unknown arrays with dynamic sizes
`UnknownArrayHandle` allows you to create a new instance of a compatible
array so that when receiving an array of unknown type, a place to put the
output can be created. However, these methods only worked if the number of
components in each value could be determined statically at compile time.
However, there are some special `ArrayHandle`s that can define the number
of components at runtime. In this case, the `ArrayHandle` would throw an
exception if `NewInstanceBasic` or `NewInstanceFloatBasic` was called.
Although rare, this condition could happen when, for example, an array was
extracted from an `UnknownArrayHandle` with `ExtractArrayFromComponents` or
with `CastAndCallWithExtractedArray` and then the resulting array was
passed to a function with arrays passed with `UnknownArrayHandle` such as
`ArrayCopy`.

@ -0,0 +1,32 @@
# Consolidate WarpScalar and WarpVector filter
In reflection, the `WarpScalar` filter is surprisingly a superset of the
`WarpVector` features. `WarpScalar` has the ability to displace in the
directions of the mesh normals. In VTK, there is a distinction of normals
to vectors, but in VTK-m it is a matter of selecting the correct one. As
such, it makes little sense to have two separate implementations for the
same operation. The filters have been combined and the interface names have
been generalized for general warping (e.g., "normal" or "vector" becomes
"direction").
In addition to consolidating the implementation, the `Warp` filter
implementation has been updated to use the modern features of VTK-m's
filter base classes. In particular, when the `Warp` filters were originally
implemented, the filter base classes did not support more than one active
scalar field, so filters like `Warp` had to manage multiple fields
themselves. The `FilterField` base class now allows specifying multiple,
indexed active fields, and the updated implementation uses this to manage
the input vectors and scalars.
The `Warp` filters have also been updated to directly support constant
vectors and scalars, which is common for `WarpScalar` and `WarpVector`,
respectively. Previously, to implement a constant field, you had to add a
field containing an `ArrayHandleConstant`. This is still supported, but an
easier method of just selecting constant vectors or scalars makes this
easier.
Internally, the implementation now uses tricks with extracting array
components to support many different array types (including
`ArrayHandleConstant`. This allows it to simultaneously interact with
coordinates, directions, and scalars without creating too many template
instances.

@ -0,0 +1,15 @@
# Added VTK-m's user guide into the source code
The VTK-m User's Guide is being transitioned into the VTK-m source code.
The implementation of the guide is being converted from LaTeX to
ReStructuredText text to be built by Sphinx. There are several goals of
this change.
1. Integrate the documentation into the source code better to better
keep the code up to date.
2. Move the documentation over to Sphinx so that it can be posted online
and be more easily linked.
3. Incoporate Doxygen into the guide to keep the documentation
consistent.
4. Build the user guide examples as part of the VTK-m CI to catch
compatibility changes quickly.

@ -0,0 +1,55 @@
##============================================================================
## Copyright (c) Kitware, Inc.
## All rights reserved.
## See LICENSE.txt for details.
##
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
##============================================================================
# This module is always loaded so that the example code is compiled as part
# of the test build. However, we only really want to build the document if
# VTKm_ENABLE_USERS_GUIDE is set.
if (NOT VTKm_ENABLE_USERS_GUIDE)
return()
endif()
set(sphinx_docs
index.rst
)
find_package(Sphinx)
if (NOT Sphinx_FOUND)
message(FATAL_ERROR
"Could not find Sphinx to build User's Guide. If you want to compile Doxygen without the User's Guide, turn off VTKm_ENABLE_USERS_GUIDE.")
endif()
option(VTKm_USERS_GUIDE_INCLUDE_TODOS
"When building the VTK-m User's Guide, specify whether to include TODO notes." ON)
mark_as_advanced(VTKm_USERS_GUIDE_INCLUDE_TODOS)
# Configuration used in conf.py.
set(doxygen_xml_output_dir "${VTKm_BINARY_DIR}/docs/doxygen/xml")
set(example_directory "${CMAKE_CURRENT_SOURCE_DIR}/examples")
if(VTKm_USERS_GUIDE_INCLUDE_TODOS)
set(include_todos "True")
else()
set(include_todos "False")
endif()
sphinx_add_docs(VTKmUsersGuideHTML
BUILDER html
SOURCE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
CONF_FILE conf.py
)
add_dependencies(VTKmUsersGuideHTML VTKmDoxygenDocs)
sphinx_add_docs(VTKmUsersGuideLaTeX
BUILDER latex
SOURCE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/latex
CONF_FILE conf.py
)
add_dependencies(VTKmUsersGuideLaTeX VTKmDoxygenDocs)

278
docs/users-guide/README.md Normal file

@ -0,0 +1,278 @@
# VTK-m User's Guide Source
This directory contains the source for building the VTK-m User's Guide. The
document is written for the [Sphinx](https://www.sphinx-doc.org/en/master/)
document generator.
## Building the documentation
To build the document, you will need the following installed on your
system.
* [Doxygen] - Processes source code to pull out documentation.
* [Sphinx] - Processes [reStructuredText] to build HTML and LaTeX
formatted documents.
* [RTD Theme] - We use the Sphinx Read the Docs theme for formatting the
generated HTML. The build will fail without this installed.
* [Sphinx CMake Domain] Sphinx does not support documenting CMake
elements out of the box. This extension provides that support.
* [Breathe] - Forms a bridge betweein Doxygen and Sphinx to allow the
Sphinx reStructuredTest to include documentation extracted by Doxygen.
To enable document generation, you first must turn on the CMake option
`VTKm_ENABLE_DOCUMENTATION`, which turns on the Doxygen documentation. With
that on, you can then turn on the `VTKm_ENABLE_USERS_GUIDE` CMake option.
The documentation will be built into HTML format in the
`docs/users-guide/html` directory in the build. It will also build LaTeX
files in `docs/users-guide/latex`. It will come with a `Makefile` that can
be used to generate a pdf form (given the proper LaTeX compiler).
## Features of the documents
The VTK-m User's Guide is built as a standard [Sphinx] project. However,
there are some features that writers should be aware of.
### Writing credit
Kenneth Moreland is the main author of this document. If you have made a
contribution, you can credit yourself in the `Contributors` section of
[acknowledgements.rst].
### Provided substitutions
The Sphinx configuration provides some convenient substitutions that can be
used throughout the document.
* `|VTKm|` This should be used whenever `VTK-m` is referenced. The
substitution contains formatting for the word.
### Expanded directives
This reStructuredText is build with some extended directives.
#### Info boxes
Two new "admonition" boxes are supported: `didyouknow` and `commonerrors`.
It is encouraged to use these boxes to highlight interesting features or
common gotchas. These are use like other tip boxes.
``` restructuredtext
.. didyouknow::
In this guide we periodically use these **Did you know?** boxes to
provide additional information related to the topic at hand.
.. commonerrors::
**Common Errors** blocks are used to highlight some of the common
problems or complications you might encounter when dealing with the
topic of discussion.
```
### Section references
It is desired for the VTK-m User's Guide to be available both online as web
pages and as a self-contained document (e.g. pdf). One issue is that
traditional paper documents work best with numbered references to parts,
chapters, and sections whereas html documents prefer descriptive links.
To service both, this document has extensions to automatically provide
references to document parts. Three roles are created: `:partref:`,
`:chapref:`, and `:secref:` to create cross references to parts, chapters,
and sections, respectively. They each take a label, and Sphinx is
configured with numfig and autosection labels. These labels take the form
<file>:<title> where <file> is the name of the file containing the section
(without the `.rst` extension) and <title> is the full name of the section.
Here are examples of cross references.
``` restructuredtext
:partref:`part-getting-started:Getting Started`
:chapref:`introduction:Introduction`
:secref:`introduction:How to Use This Guide`
```
### Example code
The VTK-m User's Guide has numerous code examples. These code examples are
pulled from source files that are compiled and run as part of VTK-m's
regression tests. Although these "tests" are not meant to be thorough
regression tests like the others, they ensure that the documentation stays
up to date and correct.
Examples are added to the `examples` directory more or less like any other
unit test in VTK-m (except by convention we start the name with
`GuideExample`). Each of these files can then be scanned to find excerpts
to include as an example in the guide.
#### Marking examples in the code
A simple text scanner goes through the example code looking for lines
containing a comment starting with 4 slashes, `////`. Any such line will
not be included in the example.
An example can be started with `//// BEGIN-EXAMPLE` and ended with
`//// END-EXAMPLE`. Each of these must be given the name of the example.
``` cpp
////
//// BEGIN-EXAMPLE EquilateralTriangle
////
vtkm::Vec<vtkm::Vec2f_32, 3> equilateralTriangle = { { 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 0.5f, 0.8660254f } };
////
//// END-EXAMPLE EquilateralTriangle
////
```
#### Loading examples in the documentation
An example can be loaded into the VTK-m User's Guide using the extended
reStructuredText `load-example` directive. The directive takes the name of
the example as its argument. `load-example` should also be given the
`:file:` and `:caption:` options.
``` restructuredtext
.. load-example:: EquilateralTriangle
:file: GuideExampleCoreDataTypes.cxx
:caption: Defining a triangle in the plane.
```
The following options are supported.
* `:file:` The filename of the file containing the named example. The
filename is relative to the `examples` directory.
* `:caption:` The caption used for the example.
* `:nolinenos:` Turn off line numbering. By default, line numbers are
shown, but they are suppressed with this option.
#### Referencing examples
The example is registered as a `code-block` the named registered as the
example named prepended with `ex:`. This name can then be referenced with
the `:ref:` and `:numref:` roles as with figures, sections, and other cross
references.
The `:numref:` role is particularly useful for referencing each example.
Using `:numref:` with just the name will be replaced with a link titled
"Example #" with "#" being the number of the example.
``` restructuredtext
:numref:`ex:EquilateralTriangle` shows how the :class:`Vec` class can be used to
store several points in the same structure.
```
The `:numref:` role also supports custom text with number substitution as
described in the [Sphinx
documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref)
``` restructuredtext
:numref:`Example %s representes an equilateral triangle<ex:EquilateralTriangle>`
using the :class:`Vec` class.
```
#### Pausing and resuming capture
Sometimes it is useful to insert code in the compiled test that is not
included as part of the example. This is useful to, for example, insert a
check for values, which can verify that the code is working correctly but
is not necessary for the example.
When a `//// PAUSE-EXAMPLE` is inserted into the code, the following lines
will not be captured until the line `//// RESUME-EXAMPLE` is encountered.
``` cpp
range.Include(2.0); // range is now [0.5 .. 2]
bool b5 = range.Contains(0.5); // b3 is true
bool b6 = range.Contains(0.6); // b4 is true
range.Include(vtkm::Range(-1, 1)); // range is now [-1 .. 2]
//// PAUSE-EXAMPLE
VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 2)), "Bad range");
//// RESUME-EXAMPLE
```
#### Referencing a specific line
You apply a label to a specific line in the code by adding a `//// LABEL`
comment right before it. The `LABEL` needs a text string used to reference
the line.
``` cpp
////
//// BEGIN-EXAMPLE VecCExample
////
//// LABEL index-to-ijk
VTKM_EXEC vtkm::VecCConst<vtkm::IdComponent> HexagonIndexToIJK(vtkm::IdComponent index)
{
static const vtkm::IdComponent HexagonIndexToIJKTable[8][3] = {
{ 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
{ 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }
};
return vtkm::make_VecC(HexagonIndexToIJKTable[index], 3);
}
//// LABEL ijk-to-index
VTKM_EXEC vtkm::IdComponent HexagonIJKToIndex(vtkm::VecCConst<vtkm::IdComponent> ijk)
{
static const vtkm::IdComponent HexagonIJKToIndexTable[2][2][2] = {
{
// i=0
{ 0, 4 }, // j=0
{ 3, 7 }, // j=1
},
{
// i=1
{ 1, 5 }, // j=0
{ 2, 6 }, // j=1
}
};
return HexagonIJKToIndexTable[ijk[0]][ijk[1]][ijk[2]];
}
////
//// END-EXAMPLE VecCExample
////
```
This line can be referenced in the text using the extended reStructuredText
`:exlineref:` role. The role takes references of the form
"example-name:line-label". If given just this reference, the link text is
"Example #, line #".
``` restructuredtext
A function to convert a 3D index to a flat index starts on
:exlineref:`VecCExample:ijk-to-index`.
```
`:exlineref:` also accepts a formatting string like the `:numref:` builtin
role. `%s` and `{line}` will be replaced with the line number.
`:exlineref:` also follows the [`:numref:`
convention](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref)
of replacing `{number}` and `{name}` with the example number and caption,
respectively.
``` restructuredtext
You can convert a flat index to a 3D index (shown starting on
:exlineref:`line {line} in Example {number}<VecCExample:index-to-ijk>`) and
the inverse function (:exlineref:`line %s<VecCExample:ijk-to-index>`).
```
### Ingesting Doxygen
The VTK-m User's Guide is built with [Breathe], which allows it to pull in
Doxygen documentation. Use [Breathe's
directives](https://breathe.readthedocs.io/en/latest/directives.html#directives)
to include the doxygen documentation.
[Sphinx]: https://www.sphinx-doc.org/en/master/
[Doxygen]: https://www.doxygen.nl/
[RTD Theme]: https://sphinx-themes.org/sample-sites/sphinx-rtd-theme/
[Sphinx CMake Domain]: https://github.com/scikit-build/moderncmakedomain
[Breathe]: https://www.breathe-doc.org/
[reStructuredText]: https://docutils.sourceforge.io/rst.html

@ -0,0 +1,139 @@
##=============================================================================
##
## 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.
##
##=============================================================================
from extract_examples import find_examples
import sphinx_tools
import docutils.nodes
import docutils.parsers.rst.directives
import sphinx.util.docutils
import re
class LoadExampleDirective(sphinx.util.docutils.SphinxDirective):
has_content = False
required_arguments = 1
option_spec = {
'file': docutils.parsers.rst.directives.unchanged,
'nolinenos': docutils.parsers.rst.directives.flag,
'caption': docutils.parsers.rst.directives.unchanged_required,
'language': docutils.parsers.rst.directives.unchanged,
'command-comment': docutils.parsers.rst.directives.unchanged,
}
def run(self):
reparse = sphinx_tools.ReparseNodes()
source_file = self.state.document.current_source
source_line = self.lineno
example_name = self.arguments[0]
filename = None
if 'file' in self.options:
filename = self.options.get('file')
if self.config.example_directory:
filename = self.config.example_directory + '/' + filename
else:
print('WARNING %s:%d: Example `%s` loaded without filename.' %
(source_file, source_line, example_name))
if 'language' in self.options:
language = self.options.get('language')
else:
language = self.config.example_language
reparse.add_line('.. code-block:: %s' % language, source_file, source_line)
reparse.add_line(' :name: ex:%s' % example_name, source_file, source_line)
if 'nolinenos' not in self.options:
reparse.add_line(' :linenos:', source_file, source_line)
if 'caption' in self.options:
reparse.add_line(' :caption: %s' % self.options.get('caption'),
source_file, source_line)
reparse.add_line('', source_file, source_line)
try:
if 'command-comment' in self.options:
command_comment = self.options.get('command-comment')
else:
command_comment = self.config.example_command_comment
example = find_examples.get_example(example_name,
filename=filename,
command_comment=command_comment)
for line in example.lines:
reparse.add_line(' %s' % line.code, example.sourcefile, line.lineno)
except Exception as e:
error = self.state_machine.reporter.error(
str(e),
docutils.nodes.literal_block(self.block_text, self.block_text),
lineno=self.lineno,
)
return [error]
reparse.add_line('', source_file, source_line)
return reparse.get_nodes(self)
def exlineref_role(name, rawtext, text, lineno, inliner, options = {}, content = []):
match = re.fullmatch(r'(.*)<(.*)>', text, re.DOTALL)
if match:
pattern = match.group(1)
ref = match.group(2)
else:
pattern = 'Example {number}, line {line}'
ref = text
match = re.fullmatch(r'(.*):([^:]*)', ref)
if not match:
message = inliner.reporter.error(
'References for :exlineref: must be of the form example-name:label-name.;'
' `%s` is invalid.' % ref, line=lineno)
problematic = inliner.problematic(rawtext, rawtext, message)
return [problematic, message]
examplename = match.group(1)
linelabel = match.group(2)
# Strip optional `ex:` prefix.
match = re.fullmatch(r'ex:(.*)', examplename)
if match:
examplename = match.group(1)
try:
example = find_examples.get_example(examplename)
if linelabel not in example.labels:
raise Exception(
'Label `%s` not in example `%s`' % (linelabel, examplename))
lineno = example.labels[linelabel]
except Exception as e:
message = inliner.reporter.error(str(e), line=lineno)
problematic = inliner.problematic(rawtext, rawtext, message)
return [problematic, message]
pattern = re.sub(r'%s', str(lineno), pattern, 1, re.DOTALL)
pattern = pattern.format(line=lineno, number='{number}', name='{name}')
if (pattern.find('{number}') >=0) or (pattern.find('{name}') >= 0):
return sphinx_tools.role_reparse(
':numref:`%s <ex:%s>`' % (pattern, examplename), lineno, inliner)
else:
return sphinx_tools.role_reparse(
':ref:`%s <ex:%s>`' % (pattern, examplename), lineno, inliner)
def setup(app):
app.add_config_value('example_directory',
default=None,
rebuild='env',
types=[str])
app.add_config_value('example_command_comment',
default='####',
rebuild='env')
app.add_config_value('example_language',
default='',
rebuild='env')
app.add_directive('load-example', LoadExampleDirective)
app.add_role('exlineref', exlineref_role)

@ -0,0 +1,160 @@
##=============================================================================
##
## 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.
##
##=============================================================================
import re
class SourceLine:
'''Class to hold lines to include as example along with line numbers.'''
def __init__(self, code, lineno):
self.code = code
self.lineno = lineno
class Example:
'''Class to hold an extracted example.
The `name` field contains the name of the example. The `lines` field
contains an array of `SourceLine` objects containing the contents.'''
def __init__(self, name, sourcefile, startline):
self.name = name
self.sourcefile = sourcefile
self.startline = startline
self.lines = []
self.labels = {}
def add_line(self, code, lineno):
self.lines.append(SourceLine(code, lineno))
class ReadError(Exception):
'''This class is thrown as an exception if a read error occurs.'''
def __init__(self, message, filename, lineno, line):
super().__init__('%s:%s: %s\n%s' % (filename, lineno, message, line))
loaded_examples = {}
loaded_files = []
def read_file(filename, command_comment='////', verbose=False):
'''Reads a source file and finds examples declared by special command
comments. This method returns an array of `Example` objects.'''
if verbose:
print('Reading file %s' % filename)
lines = open(filename, 'r').readlines()
examples = []
active_examples = {}
lineno = 0
paused = False
for line in lines:
lineno += 1
index = line.find(command_comment)
if index >= 0:
command = line[(index + len(command_comment)):].split()
if len(command) < 1:
pass
elif command[0] == 'BEGIN-EXAMPLE':
if len(command) != 2:
raise ReadError('BEGIN-EXAMPLE requires exactly one argument.',
filename,
lineno,
line)
example_name = command[1]
if verbose:
print('Extracting example `%s`' % example_name)
if example_name in active_examples:
raise ReadError('Example %s declared within itself.' % example_name,
filename,
lineno,
line)
active_examples[example_name] = Example(example_name, filename, lineno)
elif command[0] == 'END-EXAMPLE':
if len(command) != 2:
raise ReadError('END-EXAMPLE requires exactly one argument.',
filename,
lineno,
line)
example_name = command[1]
if example_name not in active_examples:
raise ReadError('Example %s ended before it began.' % example_name,
filename,
lineno,
line)
examples.append(active_examples[example_name])
del active_examples[example_name]
elif command[0] == 'PAUSE-EXAMPLE':
if paused:
raise ReadError('Example iteratively paused.',
filename, lineno, line)
paused = True
elif command[0] == 'RESUME-EXAMPLE':
if not paused:
raise ReadError('Example resumed without being paused.',
filename, lineno, line)
paused = False
elif command[0] == 'LABEL':
if len(command) != 2:
raise ReadError('LABEL requires exactly one argument.',
filename,
lineno,
line)
label = command[1]
for name in active_examples:
nextline = len(active_examples[name].lines) + 1
active_examples[name].labels[label] = nextline
else:
raise ReadError('Command %s not recognized.' % command[0],
filename,
lineno,
line)
else:
# Line not a command. Add it to any active examples.
if not paused:
for name in active_examples:
active_examples[name].add_line(line.rstrip(), lineno)
if active_examples:
raise ReadError(
'Unterminated example: %s' % next(iter(active_examples.keys())),
filename,
lineno,
line)
return examples
def load_file(filename, command_comment='////', verbose=False):
'''Loads the examples in the given file. The examples a placed in the
`loaded_examples` dictionary, which is indexed by example name. If the
file was previously loaded, nothing happens.'''
if filename not in loaded_files:
examples = read_file(filename, command_comment, verbose)
for example in examples:
name = example.name
if name in loaded_examples:
raise Exception('Example named %s found in both %s:%d and %s:%d.' %
(name, example.sourcefile, example.startline,
loaded_examples[name].sourcefile,
loaded_examples[name].startline))
loaded_examples[name] = example
loaded_files.append(filename)
def get_example(name, filename=None, command_comment='////', verbose=False):
'''Returns an `Example` object containing the named example. If a filename
is provided, that file is first scanned for examples (if it has not already
been scanned for examples).'''
if filename:
load_file(filename, command_comment, verbose)
if name not in loaded_examples:
raise Exception('No example named %s found.' % name)
example = loaded_examples[name]
if filename and filename != example.sourcefile:
print('WARNING: Example %s was expected in file %s but found in %s' %
(name, filename, example.sourcefile))
return example

@ -0,0 +1,37 @@
##=============================================================================
##
## Copyright (c) Kitware, Inc.
## All rights reserved.
## See LICENSE.txt for details.
##
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notice for more information.
##
##=============================================================================
import docutils.nodes
import sphinx_tools
def fullref_role(reftype, name, rawtext, text, lineno, inliner, options, content):
return sphinx_tools.role_reparse(
':numref:`%s {number} ({name})<%s>`' % (reftype, text),
lineno, inliner)
def partref_role(name, rawtext, text, lineno, inliner, options = {}, content = []):
return fullref_role(
'Part', name, rawtext, text, lineno, inliner, options, content)
def chapref_role(name, rawtext, text, lineno, inliner, options = {}, content = []):
return fullref_role(
'Chapter', name, rawtext, text, lineno, inliner, options, content)
def secref_role(name, rawtext, text, lineno, inliner, options = {}, content = []):
return fullref_role(
'Section', name, rawtext, text, lineno, inliner, options, content)
def setup(app):
app.add_role('partref', partref_role)
app.add_role('chapref', chapref_role)
app.add_role('secref', secref_role)

@ -0,0 +1,69 @@
##=============================================================================
##
## 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.
##
##=============================================================================
import docutils.nodes
import docutils.parsers.rst
import sphinx.util.docutils
class didyouknownode(docutils.nodes.Admonition, docutils.nodes.Element):
pass
class commonerrorsnode(docutils.nodes.Admonition, docutils.nodes.Element):
pass
def visit_didyouknow_node(self, node):
self.visit_admonition(node)
def visit_commonerrors_node(self, node):
self.visit_admonition(node)
def depart_didyouknow_node(self, node):
self.depart_admonition(node)
def depart_commonerrors_node(self, node):
self.depart_admonition(node)
class didyouknowdirective(sphinx.util.docutils.SphinxDirective):
has_content = True
def run(self):
admonitionnode = didyouknownode('\n'.join(self.content))
admonitionnode += docutils.nodes.title('Did You Know?', 'Did You Know?')
admonitionnode['classes'] += ['tip']
self.state.nested_parse(self.content, self.content_offset, admonitionnode)
return [admonitionnode]
class commonerrorsdirective(sphinx.util.docutils.SphinxDirective):
has_content = True
def run(self):
admonitionnode = commonerrorsnode('\n'.join(self.content))
admonitionnode += docutils.nodes.title('Common Errors', 'Common Errors')
admonitionnode['classes'] += ['error']
self.state.nested_parse(self.content, self.content_offset, admonitionnode)
return [admonitionnode]
def setup(app):
app.add_node(didyouknownode,
html=(visit_didyouknow_node, depart_didyouknow_node),
latex=(visit_didyouknow_node, depart_didyouknow_node),
text=(visit_didyouknow_node, depart_didyouknow_node),
)
app.add_directive('didyouknow', didyouknowdirective)
app.add_node(commonerrorsnode,
html=(visit_commonerrors_node, depart_commonerrors_node),
latex=(visit_commonerrors_node, depart_commonerrors_node),
text=(visit_commonerrors_node, depart_commonerrors_node),
)
app.add_directive('commonerrors', commonerrorsdirective)

@ -0,0 +1,109 @@
##=============================================================================
##
## 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.
##
##=============================================================================
def role_reparse(rawtext, lineno, inliner):
'''Reparses inline code for a role.
It is often the case that a role for reStructuredText can be defined using
other existing functionality. Rather than try to implement the node building
for such extensions from scratch, it is much easier to substitute the text
with something and instruct the parser to parse that.
Unfortunately, Sphinx currently does not provide the ability to do such a
"reparse" while implementing a role. This method is a hacked version of the
`parse` method of `docutils.parsers.rst.states.Inliner`. (This code might
break if the internals of that class change.)
To use this method, create a role implementation function as normal, modify
the text/rawText to the form that implements the functionality, and call
this method with the new text as well as the passed in line number and
inliner object.
Note that if the parsing of the text breaks, the error messages may be
confusing because they could refer to items that are not being directly
used in the reStructuredText document.
'''
remaining = rawtext
processed = []
unprocessed = []
messages = []
while remaining:
match = inliner.patterns.initial.search(remaining)
if match:
groups = match.groupdict()
method = inliner.dispatch[groups['start'] or groups['backquote']
or groups['refend'] or groups['fnend']]
before, inlines, remaining, sysmessages = method(inliner, match, lineno)
unprocessed.append(before)
messages += sysmessages
if inlines:
processed += inliner.implicit_inline(''.join(unprocessed), lineno)
processed += inlines
unprocessed = []
else:
break
remaining = ''.join(unprocessed) + remaining
if remaining:
processed += inliner.implicit_inline(remaining, lineno)
return processed, messages
import docutils.nodes
import docutils.statemachine
import sphinx.util.nodes
class ReparseNodes:
'''This class is used within directive classes to implement a directive by
creating new reStructuredText code. This new code is fed back to the parser
and the resulting nodes can be returned as the implementation of the
directive.
To use this class, construct an object. Then use the ``add_line`` method to
add lines one at a time. When finished, use the ``get_nodes`` function to
get the nodes that should be returned from the directives ``run`` method.
Here is a simple example::
import sphinx.util.docutils
class Foo(sphinx.util.docutils.SphinxDirective):
def run(self):
reparse = ReparseNodes()
reparse.add_line('.. note::', 'fakefile.rst', 1)
reparse.add_line(' This box added in directive.', 'fakefile.rst', 2)
reparse.add_line('', 'fakefile.rst', 3)
reparse.add_line('This text also added in directive.', 'fakefile.rst', 3)
return reparse.get_nodes(self)
def setup(app):
app.add_directive('foo', Foo)
Note that if you want the reparse to base its file location on the location
of your directive (which is a good idea), you can get the name of the file
containing the directive call with ``self.state.document.current_source``
and get the line to directive starts at with ``self.lineno``.
The implementation of this class suggested from
https://stackoverflow.com/questions/34350844/how-to-add-rst-format-in-nodes-for-directive
'''
def __init__(self):
self.source = docutils.statemachine.ViewList()
def add_line(self, sourceline, filename, linenumber):
self.source.append(sourceline, filename, linenumber)
def get_nodes(self, directive):
node = docutils.nodes.section()
node.document = directive.state.document
sphinx.util.nodes.nested_parse_with_titles(directive.state,
self.source,
node)
return node.children

@ -0,0 +1,94 @@
==============================
Acknowledgements
==============================
------------------------------
Contributors
------------------------------
.. todo:: Make sure contribution section cross references are correct.
This book includes contributions from the VTK-m community including the
VTK-m development team and the user community.
We would like to thank the following people for their significant
contributions to this text:
.. NOTE: Also make sure that the contribution list is updated in index.rst
**Vicente Bolea**, **Nickolas Davis**, **Matthew Letter**, and **Nick Thompson** for their help keeping the user's guide up to date with the |VTKm| source code.
**Sujin Philip**, **Robert Maynard**, **James Kress**, **Abhishek Yenpure**, **Mark Kim**, and **Hank Childs** for their descriptions of numerous filters.
.. Sujin Philip: Surface normals, normals in Marching Cubes
.. Robert Maynard: Gradient, warp scalars, warp vectors, histogram, extract structured
.. James Kress: Point transform
.. Abhishek Yenpure: Point merge
.. Mark Kim: ZFP compression
.. Hank Childs: Mesh Quality Metrics
**Allison Vacanti** for her documentation of..
.. several |VTKm| features in the `Extract Component Arrays`_ and `SwizzleArrays`_ sections as well as select filters.
.. Allie Vacanti filters: Surface normals.
**David Pugmire** for his documentation of..
.. partitioned data sets (Section \ref{sec:DataSets:PartitionedDataSet}) and select filters.
.. Dave Pugmire filters: Streamlines, point transform, coordinate system transforms, add ghost cells, remove ghost cells.
**Abhishek Yenpure** and **Li-Ta Lo** for their documentation of locator structures..
.. (Chapter~\ref{chap:Locators}).
.. Abhishek Yenpure: General cell locators and BoundingIntervalHierarchy
.. Li-Ta Lo: General point locators and uniform grid point locator, particle density
**Li-Ta Lo** for his documentation of random array handles and particle
density filters.
.. ArrayHandleRandomUniformBits.
**James Kress** for his documentation on |VTKm|'s testing classes.
**Manish Mathai** for his documentation of rendering features..
.. (Chapter~\ref{chap:Rendering}).
------------------------------
Funding
------------------------------
.. |LogoSpacing| image:: images/LogoSpacing.png
.. |DOELogo| image:: images/DOELogo.png
.. |ORNLLogo| image:: images/ORNLLogo.png
.. |LANLLogo| image:: images/LANLLogo.png
.. |SandiaLogo| image:: images/SandiaLogo.png
.. |KitwareLogo| image:: images/KitwareLogo.png
.. centered:: |DOELogo|
|LogoSpacing|
|ORNLLogo|
|LogoSpacing|
|LANLLogo|
|LogoSpacing|
|SandiaLogo|
|LogoSpacing|
|KitwareLogo|
|LogoSpacing|
This project has been funded in whole or in part with Federal funds from the Department of Energy, including from Oak Ridge National Laboratory, Los Alamos National Laboratory, and Sandia National Laboratories.
This manuscript has been authored in part by UT-Battelle, LLC, under contract DE-AC05-00OR22725 with the US Department of Energy (DOE).
The US government retains and the publisher, by accepting the article for publication, acknowledges that the US government retains a nonexclusive, paid-up, irrevocable, worldwide license to publish or reproduce the published form of this manuscript, or allow others to do so, for US government purposes.
Sandia National Laboratories is a multimission laboratory managed and operated by National Technology and Engineering Solutions of Sandia LLC, a wholly owned subsidiary of Honeywell International Inc. for the U.S. Department of Energy's National Nuclear Security Administration under contract DE-NA0003525.
This research was supported by the Exascale Computing Project (17-SC-20-SC), a joint project of the U.S.
Department of Energy's Office of Science and National Nuclear Security Administration, responsible for delivering a capable exascale ecosystem, including software, applications, and hardware technology, to support the nation's exascale computing imperative.
This material is based upon work supported by the U.S.
Department of Energy, Office of Science, Office of Advanced Scientific Computing Research, Scientific Discovery through Advanced Computing (SciDAC) program.

@ -0,0 +1,802 @@
==============================
Advanced Types
==============================
:chapref:`base-types:Base Types` introduced some of the base data types defined for use in |VTKm|.
However, for simplicity Chapter :chapref:`base-types:Base Types` just briefly touched the high-level concepts of these types.
In this chapter we dive into much greater depth and introduce several more types.
------------------------------
Single Number Types
------------------------------
As described in Chapter :chapref:`base-types:Base Types`, |VTKm| provides aliases for all the base C types to ensure the representation matches the variable use.
When a specific type width is not required, then the most common types to use are :type:`vtkm::FloatDefault` for floating-point numbers, :type:`vtkm::Id` for array and similar indices, and :type:`vtkm::IdComponent` for shorter-width vector indices.
If a specific type width is desired, then one of the following is used to clearly declare the type and width.
+-------+-----------------------+---------------------+----------------------+
| bytes | floating point | signed integer | unsigned integer |
+=======+=======================+=====================+======================+
| 1 | | :type:`vtkm::Int8` | :type:`vtkm::UInt8` |
+-------+-----------------------+---------------------+----------------------+
| 2 | | :type:`vtkm::Int16` | :type:`vtkm::UInt16` |
+-------+-----------------------+---------------------+----------------------+
| 4 | :type:`vtkm::Float32` | :type:`vtkm::Int32` | :type:`vtkm::UInt32` |
+-------+-----------------------+---------------------+----------------------+
| 8 | :type:`vtkm::Float64` | :type:`vtkm::Int64` | :type:`vtkm::UInt64` |
+-------+-----------------------+---------------------+----------------------+
These |VTKm|--defined types should be preferred over basic C types like ``int`` or ``float``.
------------------------------
Vector Types
------------------------------
Visualization algorithms also often require operations on short vectors.
Arrays indexed in up to three dimensions are common.
Data are often defined in 2-space and 3-space, and transformations are typically done in homogeneous coordinates of length 4.
To simplify these types of operations, |VTKm| provides the :class:`vtkm::Vec` templated type, which is essentially a fixed length array of a given type.
.. doxygenclass:: vtkm::Vec
:members:
The default constructor of :class:`vtkm::Vec` objects leaves the values uninitialized.
All vectors have a constructor with one argument that is used to initialize all components.
All :class:`vtkm::Vec` objects also have a constructor that allows you to set the individual components (one per argument).
All :class:`vtkm::Vec` objects with a size that is greater than 4 are constructed at run time and support an arbitrary number of initial values.
Likewise, there is a :func:`vtkm::make_Vec` convenience function that builds initialized vector types with an arbitrary number of components.
Once created, you can use the bracket operator to get and set component values with the same syntax as an array.
.. load-example:: CreatingVectorTypes
:file: GuideExampleCoreDataTypes.cxx
:caption: Creating vector types.
.. doxygenfunction:: vtkm::make_Vec
The types :type:`vtkm::Id2`, :type:`vtkm::Id3`, and :type:`vtkm::Id4` are type aliases of ``vtkm::Vec<vtkm::Id,2>``, ``vtkm::Vec<vtkm::Id,3>``, and ``vtkm::Vec<vtkm::Id,4>``, respectively.
These are used to index arrays of 2, 3, and 4 dimensions, which is common.
Likewise, :type:`vtkm::IdComponent2`, :type:`vtkm::IdComponent3`, and :type:`vtkm::IdComponent4` are type aliases of ``vtkm::Vec<vtkm::IdComponent,2>``, ``vtkm::Vec<vtkm::IdComponent,3>``, and ``vtkm::Vec<vtkm::IdComponent,4>``, respectively.
Because declaring :class:`vtkm::Vec` with all of its template parameters can be cumbersome, |VTKm| provides easy to use aliases for small vectors of base types.
As introduced in :secref:`base-types:Vector Types`, the following type aliases are available.
+-------+------+------------------------+------------------------+-------------------------+
| bytes | size | floating point | signed integer | unsigned integer |
+=======+======+========================+========================+=========================+
| 1 | 2 | | :type:`vtkm::Vec2i_8` | :type:`vtkm::Vec2ui_8` |
+-------+------+------------------------+------------------------+-------------------------+
| | 3 | | :type:`vtkm::Vec3i_8` | :type:`vtkm::Vec3ui_8` |
+-------+------+------------------------+------------------------+-------------------------+
| | 4 | | :type:`vtkm::Vec4i_8` | :type:`vtkm::Vec4ui_8` |
+-------+------+------------------------+------------------------+-------------------------+
| 2 | 2 | | :type:`vtkm::Vec2i_16` | :type:`vtkm::Vec2ui_16` |
+-------+------+------------------------+------------------------+-------------------------+
| | 3 | | :type:`vtkm::Vec3i_16` | :type:`vtkm::Vec3ui_16` |
+-------+------+------------------------+------------------------+-------------------------+
| | 4 | | :type:`vtkm::Vec4i_16` | :type:`vtkm::Vec4ui_16` |
+-------+------+------------------------+------------------------+-------------------------+
| 4 | 2 | :type:`vtkm::Vec2f_32` | :type:`vtkm::Vec2i_32` | :type:`vtkm::Vec2ui_32` |
+-------+------+------------------------+------------------------+-------------------------+
| | 3 | :type:`vtkm::Vec3f_32` | :type:`vtkm::Vec3i_32` | :type:`vtkm::Vec3ui_32` |
+-------+------+------------------------+------------------------+-------------------------+
| | 4 | :type:`vtkm::Vec4f_32` | :type:`vtkm::Vec4i_32` | :type:`vtkm::Vec4ui_32` |
+-------+------+------------------------+------------------------+-------------------------+
| 8 | 2 | :type:`vtkm::Vec2f_64` | :type:`vtkm::Vec2i_64` | :type:`vtkm::Vec2ui_64` |
+-------+------+------------------------+------------------------+-------------------------+
| | 3 | :type:`vtkm::Vec3f_64` | :type:`vtkm::Vec3i_64` | :type:`vtkm::Vec3ui_64` |
+-------+------+------------------------+------------------------+-------------------------+
| | 4 | :type:`vtkm::Vec4f_64` | :type:`vtkm::Vec4i_64` | :type:`vtkm::Vec4ui_64` |
+-------+------+------------------------+------------------------+-------------------------+
:class:`vtkm::Vec` supports component-wise arithmetic using the operators for plus (``+``), minus (``-``), multiply (``*``), and divide (``/``).
It also supports scalar to vector multiplication with the multiply operator.
The comparison operators equal (``==``) is true if every pair of corresponding components are true and not equal (``!=``) is true otherwise.
A special :func:`vtkm::Dot` function is overloaded to provide a dot product for every type of vector.
.. load-example:: VectorOperations
:file: GuideExampleCoreDataTypes.cxx
:caption: Vector operations.
These operators, of course, only work if they are also defined for the component type of the :class:`vtkm::Vec`.
For example, the multiply operator will work fine on objects of type ``vtkm::Vec<char,3>``, but the multiply operator will not work on objects of type ``vtkm::Vec<std::string,3>`` because you cannot multiply objects of type ``std::string``.
In addition to generalizing vector operations and making arbitrarily long vectors, :class:`vtkm::Vec` can be repurposed for creating any sequence of homogeneous objects.
Here is a simple example of using :class:`vtkm::Vec` to hold the state of a polygon.
.. load-example:: EquilateralTriangle
:file: GuideExampleCoreDataTypes.cxx
:caption: Repurposing a :class:`vtkm::Vec`.
Vec-like Types
==============================
.. index:: Vec-like
The :class:`vtkm::Vec` class provides a convenient structure for holding and passing small vectors of data.
However, there are times when using :class:`vtkm::Vec` is inconvenient or inappropriate.
For example, the size of :class:`vtkm::Vec` must be known at compile time, but there may be need for a vector whose size is unknown until compile time.
Also, the data populating a :class:`vtkm::Vec` might come from a source that makes it inconvenient or less efficient to construct a :class:`vtkm::Vec`.
For this reason, |VTKm| also provides several |Veclike| objects that behave much like :class:`vtkm::Vec` but are a different class.
These |Veclike| objects have the same interface as :class:`vtkm::Vec` except that the ``NUM_COMPONENTS`` constant is not available on those that are sized at run time.
|Veclike| objects also come with a ``CopyInto`` method that will take their contents and copy them into a standard :class:`vtkm::Vec` class.
(The standard :class:`vtkm::Vec` class also has a :func:`vtkm::Vec::CopyInto` method for consistency.)
C-Array Vec Wrapper
------------------------------
The first |Veclike| object is :class:`vtkm::VecC`, which exposes a C-type array as a :class:`vtkm::Vec`.
.. doxygenclass:: vtkm::VecC
:members:
The constructor for :class:`vtkm::VecC` takes a C array and a size of that array.
There is also a constant version of :class:`vtkm::VecC` named :class:`vtkm::VecCConst`, which takes a constant array and cannot be mutated.
.. doxygenclass:: vtkm::VecCConst
:members:
The ``vtkm/Types.h`` header defines both :class:`vtkm::VecC` and :class:`vtkm::VecCConst` as well as multiple versions of :func:`vtkm::make_VecC` to easily convert a C array to either a :class:`vtkm::VecC` or :class:`vtkm::VecCConst`.
.. doxygenfunction:: vtkm::make_VecC(T*, vtkm::IdComponent)
.. doxygenfunction:: vtkm::make_VecC(const T *array, vtkm::IdComponent size)
The following example demonstrates converting values from a constant table into a :class:`vtkm::VecCConst` for further consumption.
The table and associated methods define how 8 points come together to form a hexahedron.
.. load-example:: VecCExample
:file: GuideExampleCoreDataTypes.cxx
:caption: Using :class:`vtkm::VecCConst` with a constant array.
.. commonerrors::
The :class:`vtkm::VecC` and :class:`vtkm::VecCConst` classes only hold a pointer to a buffer that contains the data.
They do not manage the memory holding the data.
Thus, if the pointer given to :class:`vtkm::VecC` or :class:`vtkm::VecCConst` becomes invalid, then using the object becomes invalid.
Make sure that the scope of the :class:`vtkm::VecC` or :class:`vtkm::VecCConst` does not outlive the scope of the data it points to.
Variable-Sized Vec
------------------------------
The next |Veclike| object is :class:`vtkm::VecVariable`, which provides a |Veclike| object that can be resized at run time to a maximum value.
Unlike :class:`vtkm::VecC`, :class:`vtkm::VecVariable` holds its own memory, which makes it a bit safer to use.
But also unlike :class:`vtkm::VecC`, you must define the maximum size of :class:`vtkm::VecVariable` at compile time.
Thus, :class:`vtkm::VecVariable` is really only appropriate to use when there is a predetermined limit to the vector size that is fairly small.
.. doxygenclass:: vtkm::VecVariable
:members:
The following example uses a :class:`vtkm::VecVariable` to store the trace of edges within a hexahedron.
This example uses the methods defined in :numref:`ex:VecVariableExample`.
.. load-example:: VecVariableExample
:file: GuideExampleCoreDataTypes.cxx
:caption: Using :class:`vtkm::VecVariable`.
Vecs from Portals
------------------------------
|VTKm| provides further examples of |Veclike| objects as well.
For example, the :class:`vtkm::VecFromPortal` and :class:`vtkm::VecFromPortalPermute` objects allow you to treat a subsection of an arbitrarily large array as a :class:`vtkm::Vec`.
These objects work by attaching to array portals, which are described in Section~\ref{sec:ArrayPortals}.
.. todo:: Fix reference to array portals.
.. doxygenclass:: vtkm::VecFromPortal
:members:
.. doxygenclass:: vtkm::VecFromPortalPermute
:members:
Point Coordinate Vec
------------------------------
Another example of a |Veclike| object is :class:`vtkm::VecRectilinearPointCoordinates`, which efficiently represents the point coordinates in an axis-aligned hexahedron.
Such shapes are common in structured grids.
These and other data sets are described in :chapref:`dataset:Data Sets`.
------------------------------
Range
------------------------------
|VTKm| provides a convenience structure named :class:`vtkm::Range` to help manage a range of values.
The :class:`vtkm::Range` ``struct`` contains two data members, :member:`vtkm::Range::Min` and :member:`vtkm::Range::Max`, which represent the ends of the range of numbers.
:member:`vtkm::Range::Min` and :member:`vtkm::Range::Max` are both of type :type:`vtkm::Float64`.
:member:`vtkm::Range::Min` and :member:`vtkm::Range::Max` can be directly accessed, but :class:`vtkm::Range` also comes with several helper functions to make it easier to build and use ranges.
Note that all of these functions treat the minimum and maximum value as inclusive to the range.
.. doxygenstruct:: vtkm::Range
:members:
The following example demonstrates the operation of :class:`vtkm::Range`.
.. load-example:: UsingRange
:file: GuideExampleCoreDataTypes.cxx
:caption: Using :class:`vtkm::Range`.
------------------------------
Bounds
------------------------------
|VTKm| provides a convenience structure named :class:`vtkm::Bounds` to help manage
an axis-aligned region in 3D space. Among other things, this structure is
often useful for representing a bounding box for geometry. The
:class:`vtkm::Bounds` ``struct`` contains three data members,
:member:`vtkm::Bounds::X`, :member:`vtkm::Bounds::Y`, and :member:`vtkm::Bounds::Z`, which represent the range of
the bounds along each respective axis. All three of these members are of
type :class:`vtkm::Range`, which is discussed previously in :secref:`advanced-types:Range`.
:member:`vtkm::Bounds::X`, :member:`vtkm::Bounds::Y`, and :member:`vtkm::Bounds::Z` can
be directly accessed, but :class:`vtkm::Bounds` also comes with the
following helper functions to make it easier to build and use ranges.
.. doxygenstruct:: vtkm::Bounds
:members:
The following example demonstrates the operation of :class:`vtkm::Bounds`.
.. load-example:: UsingBounds
:file: GuideExampleCoreDataTypes.cxx
:caption: Using `vtkm::Bounds`.
------------------------------
Index Ranges
------------------------------
Just as it is sometimes necessary to track a range of real values, there are times when code has to specify a continuous range of values in an index sequence like an array.
For this purpose, |VTKm| provides :class:`RangeId`, which behaves similarly to :class:`Range` except for integer values.
.. doxygenstruct:: vtkm::RangeId
:members:
|VTKm| also often must operate on 2D and 3D arrays (particularly for structured cell sets).
For these use cases, :class:`RangeId2` and :class:`RangeId3` are provided.
.. doxygenstruct:: vtkm::RangeId2
:members:
.. doxygenstruct:: vtkm::RangeId3
:members:
------------------------------
Traits
------------------------------
.. index::
single: traits
single: tag
When using templated types, it is often necessary to get information about the type or specialize code based on general properties of the type.
|VTKm| uses *traits* classes to publish and retrieve information about types.
A traits class is simply a templated structure that provides type aliases for tag structures, empty types used for identification.
The traits classes might also contain constant numbers and helpful static functions.
See *Effective C++ Third Edition* by Scott Meyers for a description of traits classes and their uses.
Type Traits
==============================
.. index::
double: traits; type
The :class:`vtkm::TypeTraits` templated class provides basic information about a core type.
These type traits are available for all the basic C++ types as well as the core |VTKm| types described in :chapref:`base-types:Base Types`.
:class:`vtkm::TypeTraits` contains the following elements.
.. doxygenclass:: vtkm::TypeTraits
:members:
The :type:`vtkm::TypeTraits::NumericTag` will be an alias for one of the following tags.
.. index::
triple: tag; type; numeric
.. doxygenstruct:: vtkm::TypeTraitsRealTag
.. doxygenstruct:: vtkm::TypeTraitsIntegerTag
The :type:`vtkm::TypeTraits::DimensionalityTag` will be an alias for one of the following tags.
.. index::
triple: tag; type; dimensionality
.. doxygenstruct:: vtkm::TypeTraitsScalarTag
.. doxygenstruct:: vtkm::TypeTraitsVectorTag
If for some reason one of these tags do not apply, :type:`vtkm::TypeTraitsUnknownTag` will be used.
.. doxygenstruct:: vtkm::TypeTraitsUnknownTag
The definition of :class:`vtkm::TypeTraits` for :type:`vtkm::Float32` could like something like this.
.. load-example:: TypeTraitsImpl
:file: GuideExampleTraits.cxx
:caption: Example definition of ``vtkm::TypeTraits<vtkm::Float32>``.
Here is a simple example of using :class:`vtkm::TypeTraits` to implement a generic function that behaves like the remainder operator (``%``) for all types including floating points and vectors.
.. load-example:: TypeTraits
:file: GuideExampleTraits.cxx
:caption: Using :class:`vtkm::TypeTraits` for a generic remainder.
Vector Traits
==============================
.. index::
double: traits; vector
The templated :class:`vtkm::Vec` class contains several items for introspection (such as the component type and its size).
However, there are other types that behave similarly to :class:`vtkm::Vec` objects but have different ways to perform this introspection.
.. index:: Vec-like
For example, |VTKm| contains |Veclike| objects that essentially behave the same but might have different features.
Also, there may be reason to interchangeably use basic scalar values, like an integer or floating point number, with vectors.
To provide a consistent interface to access these multiple types that represents vectors, the :class:`vtkm::VecTraits` templated class provides information and accessors to vector types.It contains the following elements.
.. doxygenstruct:: vtkm::VecTraits
:members:
The :type:`vtkm::VecTraits::HasMultipleComponents` could be one of the following tags.
.. index::
triple: tag; vector; multiple components
.. doxygenstruct:: vtkm::VecTraitsTagMultipleComponents
.. doxygenstruct:: vtkm::VecTraitsTagSingleComponent
The :type:`vtkm::VecTraits::IsSizeStatic` could be one of the following tags.
.. index::
triple: tag; vector; static
.. doxygenstruct:: vtkm::VecTraitsTagSizeStatic
.. doxygenstruct:: vtkm::VecTraitsTagSizeVariable
The definition of :class:`vtkm::VecTraits` for :type:`vtkm::Id3` could look something like this.
.. load-example:: VecTraitsImpl
:file: GuideExampleTraits.cxx
:caption: Example definition of ``vtkm::VecTraits<vtkm::Id3>``.
The real power of vector traits is that they simplify creating generic operations on any type that can look like a vector.
This includes operations on scalar values as if they were vectors of size one.
The following code uses vector traits to simplify the implementation of :index:`less` functors that define an ordering that can be used for sorting and other operations.
.. load-example:: VecTraits
:file: GuideExampleTraits.cxx
:caption: Using :class:`vtkm::VecTraits` for less functors.
------------------------------
List Templates
------------------------------
.. index::
single: lists
single: template metaprogramming
single: metaprogramming
|VTKm| internally uses template metaprogramming, which utilizes C++ templates to run source-generating programs, to customize code to various data and compute platforms.
One basic structure often uses with template metaprogramming is a list of class names (also sometimes called a tuple or vector, although both of those names have different meanings in |VTKm|).
Many |VTKm| users only need predefined lists, such as the type lists specified in :secref:`advanced-types:Type Lists`.
Those users can skip most of the details of this section.
However, it is sometimes useful to modify lists, create new lists, or operate on lists, and these usages are documented here.
Building Lists
==============================
A basic list is defined with the :class:`vtkm::List` template.
.. doxygenstruct:: vtkm::List
It is common (but not necessary) to use the ``using`` keyword to define an alias for a list with a particular meaning.
.. load-example:: BaseLists
:file: GuideExampleLists.cxx
:caption: Creating lists of types.
|VTKm| defines some special and convenience versions of :class:`vtkm::List`.
.. doxygentypedef:: vtkm::ListEmpty
.. doxygentypedef:: vtkm::ListUniversal
Type Lists
==============================
.. index::
double: type; lists
One of the major use cases for template metaprogramming lists in |VTKm| is to identify a set of potential data types for arrays.
The :file:`vtkm/TypeList.h` header contains predefined lists for known |VTKm| types.
The following lists are provided.
.. doxygentypedef:: vtkm::TypeListId
.. doxygentypedef:: vtkm::TypeListId2
.. doxygentypedef:: vtkm::TypeListId3
.. doxygentypedef:: vtkm::TypeListId4
.. doxygentypedef:: vtkm::TypeListIdComponent
.. doxygentypedef:: vtkm::TypeListIndex
.. doxygentypedef:: vtkm::TypeListFieldScalar
.. doxygentypedef:: vtkm::TypeListFieldVec2
.. doxygentypedef:: vtkm::TypeListFieldVec3
.. doxygentypedef:: vtkm::TypeListFieldVec4
.. doxygentypedef:: vtkm::TypeListFloatVec
.. doxygentypedef:: vtkm::TypeListField
.. doxygentypedef:: vtkm::TypeListScalarAll
.. doxygentypedef:: vtkm::TypeListBaseC
.. doxygentypedef:: vtkm::TypeListVecCommon
.. doxygentypedef:: vtkm::TypeListVecAll
.. doxygentypedef:: vtkm::TypeListAll
.. doxygentypedef:: vtkm::TypeListCommon
If these lists are not sufficient, it is possible to build new type lists using the existing type lists and the list bases from :secref:`advanced-types:Building Lists` as demonstrated in the following example.
.. load-example:: CustomTypeLists
:file: GuideExampleLists.cxx
:caption: Defining new type lists.
The :file:`vtkm/cont/DefaultTypes.h` header defines a macro named :c:macro:`VTKM_DEFAULT_TYPE_LIST` that defines a default list of types to use when, for example, determining the type of a field array.
This macro can change depending on |VTKm| compile options.
Querying Lists
==============================
:file:`vtkm/List.h` contains some templated classes to help get information about a list type.
This are particularly useful for lists that are provided as templated parameters for which you do not know the exact type.
Is a List
------------------------------
The :c:macro:`VTKM_IS_LIST` does a compile-time check to make sure a particular type is actually a :class:`vtkm::List` of types.
If the compile-time check fails, then a build error will occur.
This is a good way to verify that a templated class or method that expects a list actually gets a list.
.. doxygendefine:: VTKM_IS_LIST
.. load-example:: VTKM_IS_LIST
:file: GuideExampleLists.cxx
:caption: Checking that a template parameter is a valid :class:`vtkm::List`.
List Size
------------------------------
The size of a list can be determined by using the :type:`vtkm::ListSize` template.
The type of the template will resolve to a ``std::integral_constant<vtkm::IdComponent,N>`` where ``N`` is the number of types in the list.
:type:`vtkm::ListSize` does not work with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListSize
.. load-example:: ListSize
:file: GuideExampleLists.cxx
:caption: Getting the size of a :class:`vtkm::List`.
List Contains
------------------------------
The :type:`vtkm::ListHas` template can be used to determine if a :class:`vtkm::List` contains a particular type.
:type:`vtkm::ListHas` takes two template parameters.
The first parameter is a form of :class:`vtkm::List`.
The second parameter is any type to check to see if it is in the list.
If the type is in the list, then :type:`vtkm::ListHas` resolves to ``std::true_type``.
Otherwise it resolves to ``std::false_type``.
:type:`vtkm::ListHas` always returns true for :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListHas
.. load-example:: ListHas
:file: GuideExampleLists.cxx
:caption: Determining if a :class:`vtkm::List` contains a particular type.
List Indices
------------------------------
The :type:`vtkm::ListIndexOf` template can be used to get the index of a particular type in a :class:`vtkm::List`.
:type:`vtkm::ListIndexOf` takes two template parameters.
The first parameter is a form of :class:`vtkm::List`.
The second parameter is any type to check to see if it is in the list.
The type of the template will resolve to a ``std::integral_constant<vtkm::IdComponent,N>`` where ``N`` is the index of the type.
If the requested type is not in the list, then :type:`vtkm::ListIndexOf` becomes ``std::integral_constant<vtkm::IdComponent,-1>``.
.. doxygentypedef:: vtkm::ListIndexOf
Conversely, the :type:`vtkm::ListAt` template can be used to get the type for a particular index.
The two template parameters for :type:`vtkm::ListAt` are the :class:`vtkm::List` and an index for the list.
.. doxygentypedef:: vtkm::ListAt
Neither :type:`vtkm::ListIndexOf` nor :type:`vtkm::ListAt` works with :type:`vtkm::ListUniversal`.
.. load-example:: ListIndices
:file: GuideExampleLists.cxx
:caption: Using indices with :class:`vtkm::List`.
Operating on Lists
==============================
In addition to providing the base templates for defining and querying lists, :file:`vtkm/List.h` also contains several features for operating on lists.
Appending Lists
------------------------------
The :type:`vtkm::ListAppend` template joins together 2 or more :class:`vtkm::List` types.
The items are concatenated in the order provided to :type:`vtkm::ListAppend`.
:type:`vtkm::ListAppend` does not work with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListAppend
.. load-example:: ListAppend
:file: GuideExampleLists.cxx
:caption: Appending :class:`vtkm::List` types.
Intersecting Lists
------------------------------
The :type:`vtkm::ListIntersect` template takes two :class:`vtkm::List` types and becomes a :class:`vtkm::List` containing all types in both lists.
If one of the lists is :type:`vtkm::ListUniversal`, the contents of the other list used.
.. doxygentypedef:: vtkm::ListIntersect
.. load-example:: ListIntersect
:file: GuideExampleLists.cxx
:caption: Intersecting :class:`vtkm::List` types.
Resolve a Template with all Types in a List
--------------------------------------------------
The :type:`vtkm::ListApply` template transfers all of the types in a :class:`vtkm::List` to another template.
The first template argument of :type:`vtkm::ListApply` is the :class:`vtkm::List` to apply.
The second template argument is another template to apply to.
:type:`vtkm::ListApply` becomes an instance of the passed template with all the types in the :class:`vtkm::List`.
:type:`vtkm::ListApply` can be used to convert a :class:`vtkm::List` to some other template.
:type:`vtkm::ListApply` cannot be used with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListApply
.. load-example:: ListApply
:file: GuideExampleLists.cxx
:caption: Applying a :class:`vtkm::List` to another template.
Transform Each Type in a List
------------------------------
The :type:`vtkm::ListTransform` template applies each item in a :class:`vtkm::List` to another template and constructs a list from all these applications.
The first template argument of :type:`vtkm::ListTransform` is the :class:`vtkm::List` to apply.
The second template argument is another template to apply to.
:type:`vtkm::ListTransform` becomes an instance of a new :class:`vtkm::List` containing the passed template each type.
:type:`vtkm::ListTransform` cannot be used with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListTransform
.. load-example:: ListTransform
:file: GuideExampleLists.cxx
:caption: Transforming a :class:`vtkm::List` using a custom template.
Conditionally Removing Items from a List
----------------------------------------
The :type:`vtkm::ListRemoveIf` template removes items from a :class:`vtkm::List` given a predicate.
The first template argument of :type:`vtkm::ListRemoveIf` is the :class:`vtkm::List`.
The second argument is another template that is used as a predicate to determine if the type should be removed or not.
The predicate should become a type with a ``value`` member that is a static true or false value.
Any type in the list that the predicate evaluates to true is removed.
:type:`vtkm::ListRemoveIf` cannot be used with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListRemoveIf
.. load-example:: ListRemoveIf
:file: GuideExampleLists.cxx
:caption: Removing items from a :class:`vtkm::List`.
Combine all Pairs of Two Lists
------------------------------
The :type:`vtkm::ListCross` takes two lists and performs a cross product of them.
It does this by creating a new :class:`vtkm::List` that contains nested :class:`vtkm::List` types, each of length 2 and containing all possible pairs of items in the first list with items in the second list.
:type:`vtkm::ListCross` is often used in conjunction with another list processing command, such as :type:`vtkm::ListTransform` to build templated types of many combinations.
:type:`vtkm::ListCross` cannot be used with :type:`vtkm::ListUniversal`.
.. doxygentypedef:: vtkm::ListCross
.. load-example:: ListCross
:file: GuideExampleLists.cxx
:caption: Creating the cross product of 2 :class:`vtkm::List` types.
Call a Function For Each Type in a List
----------------------------------------
The :type:`vtkm::ListForEach` function takes a functor object and a :class:`vtkm::List`.
It then calls the functor object with the default object of each type in the list.
This is most typically used with C++ run-time type information to convert a run-time polymorphic object to a statically typed (and possibly inlined) call.
.. doxygenfunction:: vtkm::ListForEach(Functor &&f, vtkm::List<Ts...>, Args&&... args)
The following example shows a rudimentary version of converting a dynamically-typed array to a statically-typed array similar to what is done in |VTKm| classes like :class:`vtkm::cont::UnknownArrayHandle` (which is documented in Chapter~\ref{chap:UnknownArrayHandle}).
.. todo:: Fix ``UnknownArrayHandle`` chapter reference above.
.. load-example:: ListForEach
:file: GuideExampleLists.cxx
:caption: Converting dynamic types to static types with :type:`vtkm::ListForEach`.
------------------------------
Pair
------------------------------
|VTKm| defines a :class:`vtkm::Pair` templated object that behaves just like ``std::pair`` from the standard template library.
The difference is that :class:`vtkm::Pair` will work in both the execution and control environments, whereas the STL ``std::pair`` does not always work in the execution environment.
.. doxygenstruct:: vtkm::Pair
:members:
:undoc-members:
The |VTKm| version of :class:`vtkm::Pair` supports the same types, fields, and operations as the STL version.
|VTKm| also provides a :func:`vtkm::make_Pair` function for convenience.
.. doxygenfunction:: vtkm::make_Pair
------------------------------
Tuple
------------------------------
|VTKm| defines a :class:`vtkm::Tuple` templated object that behaves like ``std::tuple`` from the standard template library.
The main difference is that :class:`vtkm::Tuple` will work in both the execution and control environments, whereas the STL ``std::tuple`` does not always work in the execution environment.
.. doxygenclass:: vtkm::Tuple
Defining and Constructing
==============================
:class:`vtkm::Tuple` takes any number of template parameters that define the objects stored the tuple.
.. load-example:: DefineTuple
:file: GuideExampleTuple.cxx
:caption: Defining a :class:`vtkm::Tuple`.
You can construct a :class:`vtkm::Tuple` with arguments that will be used to initialize the respective objects.
As a convenience, you can use :func:`vtkm::MakeTuple` to construct a :class:`vtkm::Tuple` of types based on the arguments.
.. doxygenfunction:: vtkm::MakeTuple
.. doxygenfunction:: vtkm::make_tuple
.. load-example:: InitTuple
:file: GuideExampleTuple.cxx
:caption: Initializing values in a :class:`vtkm::Tuple`.
Querying
==============================
The size of a :class:`vtkm::Tuple` can be determined by using the :type:`vtkm::TupleSize` template, which resolves to an ``std::integral_constant``.
The types at particular indices can be determined with :type:`vtkm::TupleElement`.
.. doxygentypedef:: vtkm::TupleSize
.. doxygentypedef:: vtkm::TupleElement
.. load-example:: TupleQuery
:file: GuideExampleTuple.cxx
:caption: Querying :class:`vtkm::Tuple` types.
The function :func:`vtkm::Get` can be used to retrieve an element from the :class:`vtkm::Tuple`.
:func:`vtkm::Get` returns a reference to the element, so you can set a :class:`vtkm::Tuple` element by setting the return value of :func:`vtkm::Get`.
.. doxygenfunction:: vtkm::Get(const vtkm::Tuple<Ts...> &tuple)
.. doxygenfunction:: vtkm::Get(vtkm::Tuple<Ts...> &tuple)
.. doxygenfunction:: vtkm::get(const vtkm::Tuple<Ts...> &tuple)
.. doxygenfunction:: vtkm::get(vtkm::Tuple<Ts...> &tuple)
.. load-example:: TupleGet
:file: GuideExampleTuple.cxx
:caption: Retrieving values from a :class:`vtkm::Tuple`.
For Each Tuple Value
==============================
The :func:`vtkm::ForEach` function takes a tuple and a function or functor and calls the function for each of the items in the tuple.
Nothing is returned from :func:`vtkm::ForEach`, and any return value from the function is ignored.
.. doxygenfunction:: vtkm::ForEach(const vtkm::Tuple<Ts...> &tuple, Function &&f)
.. doxygenfunction:: vtkm::ForEach(vtkm::Tuple<Ts...> &tuple, Function &&f)
:func:`vtkm::ForEach` can be used to check the validity of each item in a :class:`vtkm::Tuple`.
.. load-example:: TupleCheck
:file: GuideExampleTuple.cxx
:caption: Using :func:`vtkm::Tuple::ForEach` to check the contents.
:func:`vtkm::ForEach` can also be used to aggregate values in a :class:`vtkm::Tuple`.
.. load-example:: TupleAggregate
:file: GuideExampleTuple.cxx
:caption: Using :func:`vtkm::Tuple::ForEach` to aggregate.
The previous examples used an explicit ``struct`` as the functor for clarity.
However, it is often less verbose to use a C++ lambda function.
.. load-example:: TupleAggregateLambda
:file: GuideExampleTuple.cxx
:caption: Using :func:`vtkm::Tuple::ForEach` to aggregate.
Transform Each Tuple Value
==============================
The :func:`vtkm::Transform` function builds a new :class:`vtkm::Tuple` by calling a function or functor on each of the items in an existing :class:`vtkm::Tuple`.
The return value is placed in the corresponding part of the resulting :class:`vtkm::Tuple`, and the type is automatically created from the return type of the function.
.. doxygenfunction:: vtkm::Transform(const TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor(), std::forward<Function>(f)))
.. doxygenfunction:: vtkm::Transform(TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor(), std::forward<Function>(f)))
.. load-example:: TupleTransform
:file: GuideExampleTuple.cxx
:caption: Transforming a :class:`vtkm::Tuple`.
Apply
==============================
The :func:`vtkm::Apply` function calls a function or functor using the objects in a :class:`vtkm::Tuple` as the arguments.
If the function returns a value, that value is returned from :func:`vtkm::Apply`.
.. doxygenfunction:: vtkm::Apply(const vtkm::Tuple<Ts...> &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward<Function>(f), std::forward<Args>(args)...))
.. doxygenfunction:: vtkm::Apply(vtkm::Tuple<Ts...> &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward<Function>(f), std::forward<Args>(args)...))
.. load-example:: TupleApply
:file: GuideExampleTuple.cxx
:caption: Applying a :class:`vtkm::Tuple` as arguments to a function.
If additional arguments are given to :func:`vtkm::Apply`, they are also passed to the function (before the objects in the :class:`vtkm::Tuple`).
This is helpful for passing state to the function.
.. load-example:: TupleApplyExtraArgs
:file: GuideExampleTuple.cxx
:caption: Using extra arguments with :func:`vtkm::Tuple::Apply`.
.. todo:: Document ``Variant``.
------------------------------
Error Codes
------------------------------
.. index:: error codes
For operations that occur in the control environment, |VTKm| uses exceptions to report errors as described in :chapref:`error-handling:Error Handling`.
However, when operating in the execution environment, it is not feasible to throw exceptions. Thus, for operations designed for the execution environment, the status of an operation that can fail is returned as an :enum:`vtkm::ErrorCode`, which is an ``enum``.
.. doxygenenum:: vtkm::ErrorCode
If a function or method returns an :enum:`vtkm::ErrorCode`, it is a good practice to check to make sure that the returned value is :enumerator:`vtkm::ErrorCode::Success`.
If it is not, you can use the :func:`vtkm::ErrorString` function to convert the :enum:`vtkm::ErrorCode` to a descriptive C string.
The easiest thing to do from within a worklet is to call the worklet's ``RaiseError`` method.
.. doxygenfunction:: vtkm::ErrorString
.. load-example:: HandleErrorCode
:file: GuideExampleCellLocator.cxx
:caption: Checking an :enum:`vtkm::ErrorCode` and reporting errors in a worklet.

@ -0,0 +1,225 @@
==============================
Base Types
==============================
It is common for a framework to define its own types.
Even the C++ standard template library defines its own base types like :type:`std::size_t` and :type:`std::pair`.
|VTKm| is no exception.
In fact |VTKm| provides a great many base types.
It is the general coding standard of |VTKm| to not directly use the base C types like ``int`` and ``float`` and instead to use types declared in |VTKm|.
The rational is to precisely declare the representation of each variable to prevent future trouble.
Consider that you are programming something and you need to declare an integer variable.
You would declare this variable as ``int``, right?
Well, maybe.
In C++, the declaration ``int`` does not simply mean "an integer."
``int`` means something much more specific than that.
If you were to look up the C++11 standard, you would find that ``int`` is an integer represented in 32 bits with a two's complement signed representation.
In fact, a C++ compiler has no less than 8 standard integer types.
..
\footnote{%
I intentionally use the phrase ``no less than'' for our pedantic readers.
One could argue that \textcode{char} and \textcode{bool} are treated distinctly by the compiler even if their representations match either \textcode{signed char} or \textcode{unsigned char}.
Furthermore, many modern C++ compilers have extensions for less universally accepted types like 128-bit integers.
}
So, ``int`` is nowhere near as general as the code might make it seem, and treating it as such could lead to trouble.
For example, consider the MPI standard, which, back in the 1990's, implicitly selected ``int`` for its indexing needs.
Fast forward to today where there is a need to reference buffers with more than 2 billion elements, but the standard is stuck with a data type that cannot represent sizes that big.
(To be fair, it is *possible* to represent buffers this large in MPI, but it is extraordinarily awkward to do so.
Consequently, we feel that with |VTKm| it is best to declare the intention of a variable with its declaration, which should help both prevent errors and future proof code.
All the types presented in this chapter are declared in :file:`vtkm/Types.h`, which is typically included either directly or indirectly by all source using |VTKm|.
------------------------------
Floating Point Types
------------------------------
|VTKm| declares 2 types to hold floating point numbers: :type:`vtkm::Float32` and :type:`vtkm::Float64`.
These, of course, represent floating point numbers with 32-bits and 64-bits of precision, respectively.
These should be used when the precision of a floating point number is predetermined.
.. doxygentypedef:: vtkm::Float32
.. doxygentypedef:: vtkm::Float64
When the precision of a floating point number is not predetermined, operations usually have to be overloaded or templated to work with multiple precisions.
In cases where a precision must be set, but no particular precision is specified, :type:`vtkm::FloatDefault` should be used.
.. doxygentypedef:: vtkm::FloatDefault
:type:`vtkm::FloatDefault` will be set to either :type:`vtkm::Float32` or :type:`vtkm::Float64` depending on whether the CMake option :cmake:variable:`VTKm_USE_DOUBLE_PRECISION` was set when |VTKm| was compiled, as discussed in :secref:`building:Configuring |VTKm|`.
Using :type:`vtkm::FloatDefault` makes it easier for users to trade off precision and speed.
------------------------------
Integer Types
------------------------------
The most common use of an integer in |VTKm| is to index arrays.
For this purpose, the :type:`vtkm::Id` type should be used.
(The width of :type:`vtkm::Id` is determined by the :cmake:variable:`VTKm_USE_64BIT_IDS` CMake option.)
.. doxygentypedef:: vtkm::Id
|VTKm| also has a secondary index type named :type:`vtkm::IdComponent`, which is smaller and typically used for indexing groups of components within a thread.
For example, if you had an array of 3D points, you would use :type:`vtkm::Id` to reference each point, and you would use :type:`vtkm::IdComponent` to reference the respective :math:`x`, :math:`y`, and :math:`z` components.
.. doxygentypedef:: vtkm::IdComponent
.. index:: std::size_t, size_t
.. didyouknow::
The |VTKm| index types, :type:`vtkm::Id` and :type:`vtkm::IdComponent` use signed integers.
This breaks with the convention of other common index types like the C++ standard template library :type:`std::size_t`, which use unsigned integers.
Unsigned integers make sense for indices as a valid index is always 0 or greater.
However, doing things like iterating in a for loop backward, representing relative indices, and representing invalid values is much easier with signed integers.
Thus, |VTKm| chooses to use a signed integer for indexing.
|VTKm| also has types to declare an integer of a specific width and sign.
The types :type:`vtkm::Int8`, :type:`vtkm::Int16`, :type:`vtkm::Int32`, and :type:`vtkm::Int64` specify signed integers of 1, 2, 4, and 8 bytes, respectively.
Likewise, the types :type:`vtkm::UInt8`, :type:`vtkm::UInt16`, :type:`vtkm::UInt32`, and :type:`vtkm::UInt64` specify unsigned integers of 1, 2, 4, and 8 bytes, respectively.
.. doxygentypedef:: vtkm::Int8
.. doxygentypedef:: vtkm::UInt8
.. doxygentypedef:: vtkm::Int16
.. doxygentypedef:: vtkm::UInt16
.. doxygentypedef:: vtkm::Int32
.. doxygentypedef:: vtkm::UInt32
.. doxygentypedef:: vtkm::Int64
.. doxygentypedef:: vtkm::UInt64
------------------------------
Vector Types
------------------------------
Visualization algorithms also often require operations on short vectors.
Arrays indexed in up to three dimensions are common.
Data are often defined in 2-space and 3-space, and transformations are typically done in homogeneous coordinates of length 4.
To simplify these types of operations, |VTKm| provides a collection of base types to represent these short vectors, which are collectively referred to as ``Vec`` types.
:type:`vtkm::Vec2f`, :type:`vtkm::Vec3f`, and :type:`vtkm::Vec4f` specify floating point vectors of 2, 3, and 4 components, respectively.
The precision of the floating point numbers follows that of :type:`vtkm::FloatDefault` (which, as documented in :secref:`base-types:Floating Point Types`, is specified by the :cmake:variable:`VTKm_USE_DOUBLE_PRECISION` compile option).
Components of these and other ``Vec`` types can be references through the ``[ ]`` operator, much like a C array.
A ``Vec`` also supports basic arithmetic operators so that it can be used much like its scalar-value counterparts.
.. doxygentypedef:: vtkm::Vec2f
.. doxygentypedef:: vtkm::Vec3f
.. doxygentypedef:: vtkm::Vec4f
.. load-example:: SimpleVectorTypes
:file: GuideExampleCoreDataTypes.cxx
:caption: Simple use of ``Vec`` objects.
You can also specify the precision for each of these vector types by appending the bit size of each component.
For example, :type:`vtkm::Vec3f_32` and :type:`vtkm::Vec3f_64` represent 3-component floating point vectors with each component being 32 bits and 64 bits respectively.
Note that the precision number refers to the precision of each component, not the vector as a whole.
So :type:`vtkm::Vec3f_32` contains 3 32-bit (4-byte) floating point components, which means the entire :type:`vtkm::Vec3f_32` requires 96 bits (12 bytes).
.. doxygentypedef:: vtkm::Vec2f_32
.. doxygentypedef:: vtkm::Vec2f_64
.. doxygentypedef:: vtkm::Vec3f_32
.. doxygentypedef:: vtkm::Vec3f_64
.. doxygentypedef:: vtkm::Vec4f_32
.. doxygentypedef:: vtkm::Vec4f_64
To help with indexing 2-, 3-, and 4- dimensional arrays, |VTKm| provides the types :type:`vtkm::Id2`, :type:`vtkm::Id3`, and :type:`vtkm::Id4`, which are \textidentifier{Vec}s of type :type:`vtkm::Id`.
Likewise, |VTKm| provides :type:`vtkm::IdComponent2`, :type:`vtkm::IdComponent3`, and :type:`vtkm::IdComponent4`.
.. doxygentypedef:: vtkm::Id2
.. doxygentypedef:: vtkm::Id3
.. doxygentypedef:: vtkm::Id4
.. doxygentypedef:: vtkm::IdComponent2
.. doxygentypedef:: vtkm::IdComponent3
.. doxygentypedef:: vtkm::IdComponent4
|VTKm| also provides types for \textidentifier{Vec}s of integers of all varieties described in Section \ref{sec:IntegerTypes}.
:type:`vtkm::Vec2i`, :type:`vtkm::Vec3i`, and :type:`vtkm::Vec4i` are vectors of signed integers whereas :type:`vtkm::Vec2ui`, :type:`vtkm::Vec3ui`, and :type:`vtkm::Vec4ui` are vectors of unsigned integers.
All of these sport components of a width equal to :type:`vtkm::Id`.
.. doxygentypedef:: vtkm::Vec2i
.. doxygentypedef:: vtkm::Vec3i
.. doxygentypedef:: vtkm::Vec4i
.. doxygentypedef:: vtkm::Vec2ui
.. doxygentypedef:: vtkm::Vec3ui
.. doxygentypedef:: vtkm::Vec4ui
The width can be specified by appending the desired number of bits in the same way as the floating point \textidentifier{Vec}s.
For example, :type:`vtkm::Vec4ui_8` is a \textidentifier{Vec} of 4 unsigned bytes.
.. doxygentypedef:: vtkm::Vec2i_8
.. doxygentypedef:: vtkm::Vec2ui_8
.. doxygentypedef:: vtkm::Vec2i_16
.. doxygentypedef:: vtkm::Vec2ui_16
.. doxygentypedef:: vtkm::Vec2i_32
.. doxygentypedef:: vtkm::Vec2ui_32
.. doxygentypedef:: vtkm::Vec2i_64
.. doxygentypedef:: vtkm::Vec2ui_64
.. doxygentypedef:: vtkm::Vec3i_8
.. doxygentypedef:: vtkm::Vec3ui_8
.. doxygentypedef:: vtkm::Vec3i_16
.. doxygentypedef:: vtkm::Vec3ui_16
.. doxygentypedef:: vtkm::Vec3i_32
.. doxygentypedef:: vtkm::Vec3ui_32
.. doxygentypedef:: vtkm::Vec3i_64
.. doxygentypedef:: vtkm::Vec3ui_64
.. doxygentypedef:: vtkm::Vec4i_8
.. doxygentypedef:: vtkm::Vec4ui_8
.. doxygentypedef:: vtkm::Vec4i_16
.. doxygentypedef:: vtkm::Vec4ui_16
.. doxygentypedef:: vtkm::Vec4i_32
.. doxygentypedef:: vtkm::Vec4ui_32
.. doxygentypedef:: vtkm::Vec4i_64
.. doxygentypedef:: vtkm::Vec4ui_64
These types really just scratch the surface of the ``Vec`` types available in |VTKm| and the things that can be done with them.
See :chapref:`advanced-types:Advanced Types` for more information on ``Vec`` types and what can be done with them.

@ -0,0 +1,202 @@
==============================
Basic Array Handles
==============================
.. index:: array handle
:chapref:`dataset:Data Sets` describes the basic data sets used by |VTKm|.
This chapter dives deeper into how |VTKm| represents data.
Ultimately, data structures like \vtkmcont{DataSet} can be broken down into arrays of numbers.
Arrays in |VTKm| are managed by a unit called an *array handle*.
An array handle, which is implemented with the :class:`vtkm::cont::ArrayHandle` class, manages an array of data that can be accessed or manipulated by |VTKm| algorithms.
It is typical to construct an array handle in the control environment to pass data to an algorithm running in the execution environment.
It is also typical for an algorithm running in the execution environment to populate an array handle, which can then be read back in the control environment.
It is also possible for an array handle to manage data created by one |VTKm| algorithm and passed to another, remaining in the execution environment the whole time and never copied to the control environment.
.. didyouknow::
The array handle may have multiple copies of the array, one for the control environment and one for each device.
However, depending on the device and how the array is being used, the array handle will only have one copy when possible.
Copies between the environments are implicit and lazy.
They are copied only when an operation needs data in an environment where the data are not.
:class:`vtkm::cont::ArrayHandle` behaves like a shared smart pointer in that when the C++ object is copied, each copy holds a reference to the same array.
These copies are reference counted so that when all copies of the :class:`vtkm::cont::ArrayHandle` are destroyed, any allocated memory is released.
.. doxygenclass:: vtkm::cont::ArrayHandle
:members:
------------------------------
Creating Array Handles
------------------------------
:class:`vtkm::cont::ArrayHandle` is templated on the type of values being stored in the array.
There are multiple ways to create and populate an array handle.
The default :class:`vtkm::cont::ArrayHandle` constructor will create an empty array with nothing allocated in either the control or execution environment.
This is convenient for creating arrays used as the output for algorithms.
.. load-example:: CreateArrayHandle
:file: GuideExampleArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::ArrayHandle` for output data.
Chapter \ref{chap:AccessingAllocatingArrays} describes in detail how to allocate memory and access data in an :class:`vtkm::cont::ArrayHandle`.
However, you can use the :func:`vtkm::cont::make_ArrayHandle` function for a simplified way to create an :class:`vtkm::cont::ArrayHandle` with data.
:func:`vtkm::cont::make_ArrayHandle` has many forms.
An easy form to use takes an initializer list and creates a basic :class:`vtkm::cont::ArrayHandle` with it.
This allows you to create a short :class:`vtkm::cont::ArrayHandle` from literals.
.. doxygenfunction:: vtkm::cont::make_ArrayHandle(std::initializer_list<T>&&)
.. load-example:: ArrayHandleFromInitializerList
:file: GuideExampleArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::ArrayHandle` from initially specified values.
One problem with creating an array from an initializer list like this is that it can be tricky to specify the exact value type of the :class:`vtkm::cont::ArrayHandle`.
The value type of the :class:`vtkm::cont::ArrayHandle` will be the same types as the literals in the initializer list, but that might not match the type you actually need.
This is particularly true for types like :type:`vtkm::Id` and :type:`vtkm::FloatDefault`, which can change depending on compile options.
To specify the exact value type to use, give that type as a template argument to the :func:`vtkm::cont::make_ArrayHandle` function.
.. load-example:: ArrayHandleFromInitializerListTyped
:file: GuideExampleArrayHandle.cxx
:caption: Creating a typed :class:`vtkm::cont::ArrayHandle` from initially specified values.
Constructing an :class:`vtkm::cont::ArrayHandle` that points to a provided C array is also straightforward.
To do this, call :func:`vtkm::cont::make_ArrayHandle` with the array pointer, the number of values in the C array, and a :enum:`vtkm::CopyFlag`.
This last argument can be either :enumerator:`vtkm::CopyFlag::On` to copy the array or :enumerator:`vtkm::CopyFlag::Off` to share the provided buffer.
.. doxygenfunction:: vtkm::cont::make_ArrayHandle(const T*, vtkm::Id, vtkm::CopyFlag)
.. doxygenenum:: vtkm::CopyFlag
.. load-example:: ArrayHandleFromCArray
:file: GuideExampleArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::ArrayHandle` that points to a provided C array.
.. index:: vector
.. index:: std::vector
Likewise, you can use :func:`vtkm::cont::make_ArrayHandle` to transfer data from a ``std::vector`` to an :class:`vtkm::cont::ArrayHandle`.
This form of :func:`vtkm::cont::make_ArrayHandle` takes the ``std::vector`` as the first argument and a :enum:`vtkm::CopyFlag` as the second argument.
.. doxygenfunction:: vtkm::cont::make_ArrayHandle(const std::vector<T,Allocator>&, vtkm::CopyFlag)
.. load-example:: ArrayHandleFromVector
:file: GuideExampleArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::ArrayHandle` that points to a provided ``std::vector``.
As hinted at earlier, it is possible to send :enumerator:`vtkm::CopyFlag::On` to :func:`vtkm::cont::make_ArrayHandle` to wrap an :class:`vtkm::cont::ArrayHandle` around an existing C array or ``std::vector``.
Doing so allows you to send the data to the :class:`vtkm::cont::ArrayHandle` without copying it.
It also provides a mechanism for |VTKm| to write directly into your array.
However, *be aware* that if you change or delete the data provided, the internal state of :class:`vtkm::cont::ArrayHandle` becomes invalid and undefined behavior can ensue.
A common manifestation of this error happens when a ``std::vector`` goes out of scope.
This subtle interaction will cause the :class:`vtkm::cont::ArrayHandle` to point to an unallocated portion of the memory heap.
The following example provides an erroneous use of :class:`vtkm::cont::ArrayHandle` and some ways to fix it.
.. load-example:: ArrayOutOfScope
:file: GuideExampleArrayHandle.cxx
:caption: Invalidating an :class:`vtkm::cont::ArrayHandle` by letting the source ``std::vector`` leave scope.
An easy way around the problem of having an :class:`vtkm::cont::ArrayHandle`'s data going out of scope is to copy the data into the :class:`vtkm::cont::ArrayHandle`.
Simply make the :enum:`vtkm::CopyFlag` argument be :enumerator:`vtkm::CopyFlag::On` to copy the data.
This solution is shown in :exlineref:`ex:ArrayOutOfScope:CopyFlagOn`.
What if you have a ``std::vector`` that you want to pass to an :class:`vtkm::cont::ArrayHandle` and then want to only use in the :class:`vtkm::cont::ArrayHandle`?
In this case, it is wasteful to have to copy the data, but you also do not want to be responsible for keeping the ``std::vector`` in scope.
To handle this, there is a special :func:`vtkm::cont::make_ArrayHandleMove` that will move the memory out of the ``std::vector`` and into the :class:`vtkm::cont::ArrayHandle`.
:func:`vtkm::cont::make_ArrayHandleMove` takes an "rvalue" version of a ``std::vector``.
To create an "rvalue", use the ``std::move`` function provided by C++.
Once :func:`vtkm::cont::make_ArrayHandleMove` is called, the provided ``std::vector`` becomes invalid and any further access to it is undefined.
This solution is shown in :exlineref:ex:ArrayOutOfScope:MoveVector`.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleMove(std::vector<T,Allocator>&&)
.. doxygenfunction:: vtkm::cont::make_ArrayHandle(std::vector<T,Allocator>&&, vtkm::CopyFlag)
.. todo:: Document moving basic C arrays somewhere.
------------------------------
Deep Array Copies
------------------------------
.. index::
double: array handle; deep copy
As stated previously, an :class:`vtkm::cont::ArrayHandle` object behaves as a smart pointer that copies references to the data without copying the data itself.
This is clearly faster and more memory efficient than making copies of the data itself and usually the behavior desired.
However, it is sometimes the case that you need to make a separate copy of the data.
The easiest way to copy an :class:`vtkm::cont::ArrayHandle` is to use the :func:`vtkm::cont::ArrayHandle::DeepCopyFrom` method.
.. load-example:: ArrayHandleDeepCopy
:file: GuideExampleArrayHandle.cxx
:caption: Deep copy a :class:`vtkm::cont::ArrayHandle` of the same type.
However, the :func:`vtkm::cont::ArrayHandle::DeepCopyFrom` method only works if the two :class:`vtkm::cont::ArrayHandle` objects are the exact same type.
To simplify copying the data between :class:`vtkm::cont::ArrayHandle` objects of different types, |VTKm| comes with the :func:`vtkm::cont::ArrayCopy` convenience function defined in ``vtkm/cont/ArrayCopy.h``.
:func:`vtkm::cont::ArrayCopy` takes the array to copy from (the source) as its first argument and the array to copy to (the destination) as its second argument.
The destination array will be properly reallocated to the correct size.
.. load-example:: ArrayCopy
:file: GuideExampleRuntimeDeviceTracker.cxx
:caption: Using :func:`vtkm::cont::ArrayCopy`.
.. doxygenfunction:: vtkm::cont::ArrayCopy(const SourceArrayType&, DestArrayType&)
.. doxygenfunction:: vtkm::cont::ArrayCopy(const SourceArrayType&, vtkm::cont::UnknownArrayHandle&)
----------------------------------------
The Hidden Second Template Parameter
----------------------------------------
.. index::
double: array handle; storage
We have already seen that :class:`vtkm::cont::ArrayHandle` is a templated class with the template parameter indicating the type of values stored in the array.
However, :class:`vtkm::cont::ArrayHandle` has a second hidden parameter that indicates the \keyterm{storage} of the array.
We have so far been able to ignore this second template parameter because |VTKm| will assign a default storage for us that will store the data in a basic array.
Changing the storage of an :class:`vtkm::cont::ArrayHandle` lets us do many weird and wonderful things.
We will explore these options in later chapters, but for now we can ignore this second storage template parameter.
However, there are a couple of things to note concerning the storage.
First, if the compiler gives an error concerning your use of :class:`vtkm::cont::ArrayHandle`, the compiler will report the :class:`vtkm::cont::ArrayHandle` type with not one but two template parameters.
A second template parameter of :struct:`vtkm::cont::StorageTagBasic` can be ignored.
Second, if you write a function, method, or class that is templated based on an :class:`vtkm::cont::ArrayHandle` type, it is good practice to accept an :class:`vtkm::cont::ArrayHandle` with a non-default storage type.
There are two ways to do this.
The first way is to template both the value type and the storage type.
.. load-example:: ArrayHandleParameterTemplate
:file: GuideExampleArrayHandle.cxx
:caption: Templating a function on an :class:`vtkm::cont::ArrayHandle`'s parameters.
The second way is to template the whole array type rather than the sub types.
If you create a template where you expect one of the parameters to be an :class:`vtkm::cont::ArrayHandle`, you should use the :c:macro:`VTKM_IS_ARRAY_HANDLE` macro to verify that the type is indeed an :class:`vtkm::cont::ArrayHandle`.
.. doxygendefine:: VTKM_IS_ARRAY_HANDLE
.. load-example:: ArrayHandleFullTemplate
:file: GuideExampleArrayHandle.cxx
:caption: A template parameter that should be an :class:`vtkm::cont::ArrayHandle`.
------------------------------
Mutability
------------------------------
.. index:: array handle; const
One subtle feature of :class:`vtkm::cont::ArrayHandle` is that the class is, in principle, a pointer to an array pointer.
This means that the data in an :class:`vtkm::cont::ArrayHandle` is always mutable even if the class is declared ``const``.
You can change the contents of "constant" arrays via methods like :func:`vtkm::cont::ArrayHandle::WritePortal` and :func:`vtkm::cont::ArrayHandle::PrepareForOutput`.
It is even possible to change the underlying array allocation with methods like :func:`vtkm::cont::ArrayHandle::Allocate` and :func:`vtkm::cont::ArrayHandle::ReleaseResources`.
The upshot is that you can (sometimes) pass output arrays as constant :class:`vtkm::cont::ArrayHandle` references.
So if a constant :class:`vtkm::cont::ArrayHandle` can have its contents modified, what is the difference between a constant reference and a non-constant reference?
The difference is that the constant reference can change the array's content, but not the array itself.
Basically, this means that you cannot perform shallow copies into a ``const`` :class:`vtkm::cont::ArrayHandle`.
This can be a pretty big limitation, and many of |VTKm|'s internal device algorithms still require non-constant references for outputs.

@ -0,0 +1,135 @@
==============================
Basic Filter Implementation
==============================
.. index:: filter; implementation
:chapref:`simple-worklets:Simple Worklets` introduced the concept of a worklet and demonstrated how to create and run one to execute an algorithm on a device.
Although worklets provide a powerful mechanism for designing heavily threaded visualization algorithms, invoking them requires quite a bit of knowledge of the workings of |VTKm|.
Instead, most users execute algorithms in |VTKm| using filters.
Thus, to expose algorithms implemented with worklets to general users, we need to implement a filter to encapsulate the worklets.
In this chapter we will create a filter that encapsulates the worklet algorithm presented in :chapref:`simple-worklets:Simple Worklets`, which converted the units of a pressure field from pounds per square inch (psi) to Newtons per square meter (:math:`\mathrm{N}/\mathrm{m}^2`).
Filters in |VTKm| are implemented by deriving :class:`vtkm::filter::Filter`.
.. Comment this out. Too much duplicate documentation makes it confusing.
doxygenclass:: vtkm::filter::Filter
The following example shows the declaration of our pressure unit conversion filter.
|VTKm| filters are divided into libraries.
In this example, we are assuming this filter is being compiled in a library named ``vtkm::filter::unit_conversion``.
By convention, the source files would be placed in a directory named ``vtkm/filter/unit_conversion``.
.. load-example:: SimpleField
:file: GuideExampleSimpleAlgorithm.cxx
:caption: Header declaration for a simple filter.
It is typical for a filter to have a constructor to set up its initial state.
A filter will also override the :func:`vtkm::filter::Filter::DoExecute` method.
The :func:`vtkm::filter::Filter::DoExecute` method takes a :class:`vtkm::cont::DataSet` as input and likewise returns a :class:`vtkm::cont::DataSet` containing the results of the filter operation.
.. doxygenfunction:: vtkm::filter::Filter::DoExecute
Note that the declaration of the ``PoundsPerSquareInchToNewtonsPerSquareMeterFilter`` contains the export macro ``VTKM_FILTER_UNIT_CONVERSION_EXPORT``.
This is a macro generated by CMake to handle the appropriate modifies for exporting a class from a library.
Remember that this code is to be placed in a library named ``vtkm::filter::unit_conversion``.
For this library, CMake creates a header file named ``vtkm/filter/unit_conversion.h`` that declares macros like ``VTKM_FILTER_UNIT_CONVERSION_EXPORT``.
.. didyouknow::
A filter can also override the :func:`vtkm::filter::Filter::DoExecutePartitions`, which operates on a :class:`vtkm::cont::PartitionedDataSet`.
If :func:`vtkm::filter::Filter::DoExecutePartitions` is not overridden, then the filter will call :func:`vtkm::filter::Filter::DoExecute` on each of the partitions and build a new :class:`vtkm::cont::PartitionedDataSet` with the outputs.
.. doxygenfunction:: vtkm::filter::Filter::DoExecutePartitions
Once the filter class is declared in the ``.h`` file, the filter implementation is by convention given in a separate ``.cxx`` file.
Given the definition of our filter in :numref:`ex:SimpleField`, we will need to provide the implementation for the constructor and the :func:`vtkm::filter::Filter::DoExecute` method.
The constructor is quite simple.
It initializes the name of the output field name, which is managed by the superclass.
.. load-example:: SimpleFieldConstructor
:file: GuideExampleSimpleAlgorithm.cxx
:caption: Constructor for a simple filter.
In this case, we are setting the output field name to the empty string.
This is not to mean that the default name of the output field should be the empty string, which is not a good idea.
Rather, as we will see later, we will use the empty string to flag an output name that should be derived from the input name.
The meat of the filter implementation is located in the :func:`vtkm::filter::Filter::DoExecute` method.
.. load-example:: SimpleFieldDoExecute
:file: GuideExampleSimpleAlgorithm.cxx
:caption: Implementation of ``DoExecute`` for a simple filter.
The single argument to :func:`vtkm::filter::Filter::DoExecute` is a :class:`vtkm::cont::DataSet` containing the data to operate on, and :func:`vtkm::filter::Filter::DoExecute` returns a derived :class:`vtkm::cont::DataSet`.
The filter must pull the appropriate information out of the input :class:`vtkm::cont::DataSet` to operate on.
This simple algorithm just operates on a single field array of the data.
The :class:`vtkm::filter::Filter` base class provides several methods, documented in :secref:`running-filters:Input Fields`, to allow filter users to select the active field to operate on.
The filter implementation can get the appropriate field to operate on using the :func:`vtkm::filter::Filter::GetFieldFromDataSet` method as shown in :exlineref:`ex:SimpleFieldDoExecute:InputField`.
.. doxygenfunction:: vtkm::filter::Filter::GetFieldFromDataSet(const vtkm::cont::DataSet&) const
.. doxygenfunction:: vtkm::filter::Filter::GetFieldFromDataSet(vtkm::IdComponent, const vtkm::cont::DataSet&) const
One of the challenges with writing filters is determining the actual types the algorithm is operating on.
The :class:`vtkm::cont::Field` object pulled from the input :class:`vtkm::cont::DataSet` contains a :class:`vtkm::cont::ArrayHandle` (see :chapref:`basic-array-handles:Basic Array Handles`), but you do not know what the template parameters of the :class:`vtkm::cont::ArrayHandle` are.
There are numerous ways to extract an array of an unknown type out of a :class:`vtkm::cont::ArrayHandle` (many of which will be explored later in Chapter \ref{chap:UnknownArrayHandle}), but the :class:`vtkm::filter::Filter` contains some convenience functions to simplify this.
.. todo:: Fix above reference to unknown array handle chapter.
In particular, this filter operates specifically on scalar fields.
For this purpose, :class:`vtkm::filter::Filter` provides the :func:`vtkm::filter::Filter::CastAndCallScalarField` helper method.
The first argument to :func:`vtkm::filter::Filter::CastAndCallScalarField` is the field containing the data to operate on.
The second argument is a functor that will operate on the array once it is identified.
:func:`vtkm::filter::Filter::CastAndCallScalarField` will pull a :class:`vtkm::cont::ArrayHandle` out of the field and call the provided functor with that object.
:func:`vtkm::filter::Filter::CastAndCallScalarField` is called in :exlineref:`ex:SimpleFieldDoExecute:CastAndCall`.
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallScalarField(const vtkm::cont::UnknownArrayHandle&, Functor&&, Args&&...) const
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallScalarField(const vtkm::cont::Field&, Functor&&, Args&&...) const
.. didyouknow::
If your filter requires a field containing :type:`vtkm::Vec` valuess of a particular size (e.g. 3), you can use the convenience method :func:`vtkm::filter::Filter::CastAndCallVecField`.
:func:`vtkm::filter::Filter::CastAndCallVecField` works similarly to :func:`vtkm::filter::Filter::CastAndCallScalarField` except that it takes a template parameter specifying the size of the :type:`vtkm::Vec`.
For example, ``vtkm::filter::Filter::CastAndCallVecField<3>(inField, functor);``.
As previously stated, one of the arguments to :func:`vtkm::filter::Filter::CastAndCallScalarField` is a functor that contains the routine to call with the found :class:`vtkm::cont::ArrayHandle`.
A functor can be created as its own ``class`` or ``struct``, but a more convenient method is to use a C++ lambda.
A lambda is an unnamed function defined inline with the code.
The lambda in :numref:`ex:SimpleFieldDoExecute` starts on :exlineref:`line {line}<ex:SimpleFieldDoExecute:Lambda>`.
Apart from being more convenient than creating a named class, lambda functions offer another important feature.
Lambda functions can "capture" variables in the current scope.
They can therefore access things like local variables and the ``this`` reference to the method's class (even accessing private members).
The callback to the lambda function in :numref:`ex:SimpleFieldDoExecute` first creates an output :class:`vtkm::cont::ArrayHandle` of a compatible type (:exlineref:`line {line}<ex:SimpleFieldDoExecute:CreateOutputArray>`), then invokes the worklet that computes the derived field (:exlineref:`line {line}<ex:SimpleFieldDoExecute:Invoke>`), and finally captures the resulting array.
Note that the :class:`vtkm::filter::Filter` base class provides a :func:`vtkm::filter::Filter::Invoke` member that can be used to invoke the worklet.
(See :secref:`simple-worklets:Invoking a Worklet` for information on invoking a worklet.)
Recall that the worklet created in :chapref:`simple-worklets:Simple Worklets` takes two parameters: an input array and an output array, which are shown in this invocation.
With the output data created, the filter has to build the output structure to return.
All implementations of :func:`vtkm::filter::Filter::DoExecute` must return a :class:`vtkm::cont::DataSet`, and for a simple field filter like this we want to return the same :class:`vtkm::cont::DataSet` as the input with the output field added.
The output field needs a name, and we get the appropriate name from the superclass (:exlineref:`ex:SimpleFieldDoExecute:OutputName`).
However, we would like a special case where if the user does not specify an output field name we construct one based on the input field name.
Recall from :numref:`ex:SimpleFieldConstructor` that by default we set the output field name to the empty string.
Thus, our filter checks for this empty string, and if it is encountered, it builds a field name by appending "_N/M^2" to it.
Finally, our filter constructs the output :class:`vtkm::cont::DataSet` using one of the :func:`vtkm::filter::Filter::CreateResult` member functions (:exlineref:`ex:SimpleFieldDoExecute:CreateResult`).
In this particular case, the filter uses :func:`vtkm::filter::Filter::CreateResultField`, which constructs a :class:`vtkm::cont::DataSet` with the same structure as the input and adds the computed filter.
.. doxygenfunction:: vtkm::filter::Filter::CreateResult(const vtkm::cont::DataSet&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResult(const vtkm::cont::PartitionedDataSet&, const vtkm::cont::PartitionedDataSet&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResult(const vtkm::cont::PartitionedDataSet&, const vtkm::cont::PartitionedDataSet&, FieldMapper&&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResult(const vtkm::cont::DataSet&, const vtkm::cont::UnknownCellSet&, FieldMapper&&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultField(const vtkm::cont::DataSet&, const vtkm::cont::Field&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultField(const vtkm::cont::DataSet&, const std::string&, vtkm::cont::Field::Association, const vtkm::cont::UnknownArrayHandle&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultFieldPoint(const vtkm::cont::DataSet&, const std::string&, const vtkm::cont::UnknownArrayHandle&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultFieldCell(const vtkm::cont::DataSet&, const std::string&, const vtkm::cont::UnknownArrayHandle&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultCoordinateSystem(const vtkm::cont::DataSet&, const vtkm::cont::UnknownCellSet&, const vtkm::cont::CoordinateSystem&, FieldMapper&&) const
.. doxygenfunction:: vtkm::filter::Filter::CreateResultCoordinateSystem(const vtkm::cont::DataSet&, const vtkm::cont::UnknownCellSet&, const std::string&, const vtkm::cont::UnknownArrayHandle&, FieldMapper&&) const
.. commonerrors::
The :func:`vtkm::filter::Filter::CreateResult` methods do more than just construct a new :class:`vtkm::cont::DataSet`.
They also set up the structure of the data and pass fields as specified by the state of the filter object.
Thus, implementations of :func:`vtkm::filter::Filter::DoExecute` should always return a :class:`vtkm::cont::DataSet` that is created with :func:`vtkm::filter::Filter::CreateResult` or a similarly named method in the base filter class.
This chapter has just provided a brief introduction to creating filters.
There are several more filter superclasses to help express algorithms of different types.
After some more worklet concepts to implement more complex algorithms are introduced in :partref:`part-advanced:Advanced Development`, we will see a more complete documentation of the types of filters in :chapref:`extended-filter-impl:Extended Filter Implementations`.

@ -0,0 +1,399 @@
==============================
Building and Installing |VTKm|
==============================
Before we begin describing how to develop with |VTKm|, we have a brief overview of how to build |VTKm|, optionally install it on your system, and start your own programs that use |VTKm|.
------------------------------
Getting |VTKm|
------------------------------
|VTKm| is an open source software product where the code is made freely available.
To get the latest released version of |VTKm|, go to the |VTKm| releases page:
https://gitlab.kitware.com/vtk/vtk-m/-/releases
From there with your favorite browser you may download the source code from any of the recent |VTKm| releases in a variety of different archive files such as zip or tar gzip.
For access to the most recent work, the |VTKm| development team provides public anonymous read access to their main source code repository.
The main |VTKm| repository on a GitLab instance hosted at Kitware, Inc.
The repository can be browsed from its project web page:
https://gitlab.kitware.com/vtk/vtk-m
We leave access to the :index:`git` hosted repository as an exercise for the user.
Those interested in :command:`git` access for the purpose of contributing to |VTKm| should consult the `CONTRIBUTING <https://gitlab.kitware.com/vtk/vtk-m/blob/master/CONTRIBUTING.md>`_ guidelines documented in the source code.
.. %% \index{git|(}
.. %% The source code in the |VTKm| repository is access through the \textfilename{git} version control tool.
.. %% If you have not used \textfilename{git} before, there are several resources available to help you get familiar with it.
.. %% Github has a nice setup guide (\url{https://help.github.com/articles/set-up-git}) to help you get up and running quickly.
.. %% For more complete documentation, we recommend the \emph{Pro Git} book (\url{https://git-scm.com/book}).
.. %% To get a copy of the |VTKm| repository, issue a git clone command.
.. %% \begin{blankexample}{Cloning the main |VTKm| git repository.}
.. %% git clone https://gitlab.kitware.com/vtk/vtk-m.git
.. %% \end{blankexample}
.. %% The git clone command will create a copy of all the source code to your local machine.
.. %% As time passes and you want to get an update of changes in the repository, you can do that with the git pull command.
.. %% \begin{blankexample}{Updating a git repository with the pull command.}
.. %% git pull
.. %% \end{blankexample}
.. %% \begin{didyouknow}
.. %% The proceeding examples for using git are based on the \textfilename{git} command line tool, which is particularly prevalent on Unix-based and Mac systems.
.. %% There also exist several GUI tools for accessing git repositories.
.. %% These tools each have their own interface and they can be quite different.
.. %% However, they all should have roughly equivalent commands named ``clone'' to download a repository given a url and ``pull'' to update an existing repository.
.. %% \end{didyouknow}
.. %% \index{git|)}
------------------------------
Configuring |VTKm|
------------------------------
.. index::
single: CMake
pair: CMake; configuration
|VTKm| uses a cross-platform configuration tool named CMake to simplify the configuration and building across many supported platforms.
CMake is available from many package distribution systems and can also be downloaded for many platforms from http://cmake.org.
Most distributions of CMake come with a convenient GUI application (:command:`cmake-gui`) that allows you to browse all of the available configuration variables and run the configuration.
Many distributions also come with an alternative terminal-based version (:command:`ccmake`), which is helpful when accessing remote systems where creating GUI windows is difficult.
One helpful feature of CMake is that it allows you to establish a build directory separate from the source directory, and the |VTKm| project requires that separation.
Thus, when you run CMake for the first time, you want to set the build directory to a new empty directory and the source to the downloaded or cloned files.
The following example shows the steps for the case where the |VTKm| source is cloned from the git repository.
(If you extracted files from an archive downloaded from the |VTKm| web page, the instructions are the same from the second line down.)
.. code-block:: bash
:caption: Running CMake on downloaded |VTKm| source (Unix commands).
:name: ex:RunningCMake
tar xvzf ~/Downloads/vtk-m-v2.1.0.tar.gz
mkdir vtkm-build
cd vtkm-build
cmake-gui ../vtk-m-v2.1.0
.. _fig:CMakeGUI:
.. figure:: images/CMakeGUIBoth.png
:width: 100%
:align: center
The CMake GUI configuring the |VTKm| project.
At left is the initial blank configuration.
At right is the state after a configure pass.
The first time the CMake GUI runs, it initially comes up blank as shown at left in :numref:`fig:CMakeGUI`.
Verify that the source and build directories are correct (located at the top of the GUI) and then click the :guilabel:`Configure` button near the bottom.
The first time you run configure, CMake brings up a dialog box asking what generator you want for the project.
This allows you to select what build system or IDE to use (e.g. make, ninja, Visual Studio).
Once you click :guilabel:`Finish`, CMake will perform its first configuration.
Don't worry if CMake gives an error about an error in this first configuration process.
.. commonerrors::
Most options in CMake can be reconfigured at any time, but not the compiler and build system used.
These must be set the first time configure is run and cannot be subsequently changed.
If you want to change the compiler or the project file types, you will need to delete everything in the build directory and start over.
After the first configuration, the CMake GUI will provide several configuration options as shown in :numref:`fig:CMakeGUI` on the right.
You now have a chance to modify the configuration of |VTKm|, which allows you to modify both the behavior of the compiled |VTKm| code as well as find components on your system.
Using the CMake GUI is usually an iterative process where you set configuration options and re-run :guilabel:`Configure`.
Each time you configure, CMake might find new options, which are shown in red in the GUI.
It is often the case during this iterative configuration process that configuration errors occur.
This can occur after a new option is enabled but CMake does not automatically find the necessary libraries to make that feature possible.
For example, to enable TBB support, you may have to first enable building TBB, configure for TBB support, and then tell CMake where the TBB include directories and libraries are.
Once you have set all desired configuration variables and resolved any CMake errors, click the :guilabel:`Generate` button. This will create the build files (such as makefiles or project files depending on the generator chosen at the beginning). You can then close the CMake GUI.
There are a great number of configuration parameters available when running CMake on |VTKm|.
The following list contains the most common configuration parameters.
.. cmake:variable:: BUILD_SHARED_LIBS
Determines whether static or shared libraries are built.
.. cmake:variable:: CMAKE_BUILD_TYPE
Selects groups of compiler options from categories like :index:`Debug` and :index:`Release`.
Debug builds are, obviously, easier to debug, but they run *much* slower than Release builds.
Use Release builds whenever releasing production software or doing performance tests.
.. cmake:variable:: CMAKE_INSTALL_PREFIX
The root directory to place files when building the install target.
.. cmake:variable:: VTKm_ENABLE_EXAMPLES
The |VTKm| repository comes with an \textfilename{examples} directory.
This macro determines whether they are built.
.. cmake:variable:: VTKm_ENABLE_BENCHMARKS
If on, the |VTKm| build includes several benchmark programs.
The benchmarks are regression tests for performance.
.. cmake:variable:: VTKm_ENABLE_CUDA
Determines whether |VTKm| is built to run on :index:`CUDA` GPU devices.
.. index:: kokkos
.. cmake:variable:: VTKm_ENABLE_KOKKOS
Determines whether |VTKm| is built using the `Kokkos <https://kokkos.github.io/kokkos-core-wiki/>`_ portable library.
Kokkos, can be configured to support several backends that |VTKm| can leverage.
.. cmake:variable:: VTKm_ENABLE_MPI
Determines whether |VTKm| is built with :index:`MPI` suppoert for running on distributed memory clusters.
.. cmake:variable:: VTKm_ENABLE_OPENMP
Determines whether |VTKm| is built to run on multi-core devices using :index:`OpenMP` pragmas provided by the C++ compiler.
.. cmake:variable:: VTKm_ENABLE_RENDERING
Determines whether to build the rendering library.
.. index:: see: Intel Threading Building Blocks; TBB
.. index:: TBB
.. cmake:variable:: VTKm_ENABLE_TBB
Determines whether |VTKm| is built to run on multi-core x86 devices using the Intel Threading Building Blocks library.
.. cmake:variable:: VTKm_ENABLE_TESTING
If on, the |VTKm| build includes building many test programs.
The |VTKm| source includes hundreds of regression tests to ensure quality during development.
.. cmake:variable:: VTKm_ENABLE_TUTORIALS
If on, several small example programes used for the |VTKm| tutorial are built.
.. cmake:variable:: VTKm_USE_64BIT_IDS
If on, then |VTKm| will be compiled to use 64-bit integers to index arrays and other lists.
If off, then |VTKm| will use 32-bit integers.
32-bit integers take less memory but could cause failures on larger data.
.. cmake:variable:: VTKm_USE_DOUBLE_PRECISION
If on, then |VTKm| will use double precision (64-bit) floating point numbers for calculations where the precision type is not otherwise specified.
If off, then single precision (32-bit) floating point numbers are used.
Regardless of this setting, |VTKm|'s templates will accept either type.
------------------------------
Building |VTKm|
------------------------------
Once CMake successfully configures |VTKm| and generates the files for the build system, you are ready to build |VTKm|.
As stated earlier, CMake supports generating configuration files for several different types of build tools.
Make and ninja are common build tools, but CMake also supports building project files for several different types of integrated development environments such as Microsoft Visual Studio and Apple XCode.
The |VTKm| libraries and test files are compiled when the default build is invoked.
For example, if a :file:`Makefile` was generated, the build is invoked by calling \textfilename{make} in the build directory.
Expanding on :numref:`ex:RunningCMake`
.. code-block:: bash
:caption: Using :command:`make` to build |VTKm|.
:name: ex:RunningMake
tar xvzf ~/Downloads/vtk-m-v2.1.0.tar.gz
mkdir vtkm-build
cd vtkm-build
cmake-gui ../vtk-m-v2.1.0
make -j
make install
.. didyouknow::
:file:`Makefile` and other project files generated by CMake support parallel builds, which run multiple compile steps simultaneously.
On computers that have multiple processing cores (as do almost all modern computers), this can significantly speed up the overall compile.
Some build systems require a special flag to engage parallel compiles.
For example, :command:`make` requires the ``-j`` flag to start parallel builds as demonstrated in :numref:`ex:RunningMake`.
.. didyouknow::
:numref:`ex:RunningMake` assumes that a make build system was generated, which is the default on most system.
However, CMake supports many more build systems, which use different commands to run the build.
If you are not sure what the appropriate build command is, you can run ``cmake --build`` to allow CMake to start the build using whatever build system is being used.
.. commonerrors::
CMake allows you to switch between several types of builds including default, Debug, and Release.
Programs and libraries compiled as release builds can run *much* faster than those from other types of builds.
Thus, it is important to perform Release builds of all software released for production or where runtime is a concern.
Some integrated development environments such as Microsoft Visual Studio allow you to specify the different build types within the build system.
But for other build programs, like :command:`make`, you have to specify the build type in the :cmake:variable:`CMAKE_BUILD_TYPE` CMake configuration variable, which is described in :secref:`building:Configuring |VTKm|`.
CMake creates several build "targets" that specify the group of things to build.
The default target builds all of |VTKm|'s libraries as well as tests, examples, and benchmarks if enabled.
The ``test`` target executes each of the |VTKm| regression tests and verifies they complete successfully on the system.
The ``install`` target copies the subset of files required to use |VTKm| to a common installation directory.
The ``install`` target may need to be run as an administrator user if the installation directory is a system directory.
.. didyouknow::
|VTKm| contains a significant amount of regression tests.
If you are not concerned with testing a build on a given system, you can turn off building the testing, benchmarks, and examples using the CMake configuration variables described in :secref:`building:Configuring |VTKm|`.
This can shorten the |VTKm| compile time.
------------------------------
Linking to |VTKm|
------------------------------
Ultimately, the value of |VTKm| is the ability to link it into external projects that you write.
The header files and libraries installed with |VTKm| are typical, and thus you can link |VTKm| into a software project using any type of build system.
However, |VTKm| comes with several CMake configuration files that simplify linking |VTKm| into another project that is also managed by CMake.
Thus, the documentation in this section is specifically for finding and configuring |VTKm| for CMake projects.
.. index::
pair: CMake; VTK-m package
|VTKm| can be configured from an external project using the :cmake:command:`find_package` CMake function.
The behavior and use of this function is well described in the CMake documentation.
The first argument to :cmake:command:`find_package` is the name of the package, which in this case is ``VTKm``.
CMake configures this package by looking for a file named :file:`VTKmConfig.cmake`, which will be located in the :file:`lib/cmake/vtkm-<\VTKm version>` directory of the install or build of |VTKm|.
The configurable CMake variable :cmake:variable:`CMAKE_PREFIX_PATH` can be set to the build or install directory, the :cmake:envvar:`CMAKE_PREFIX_PATH` environment variable can likewise be set, or \cmakevar{VTKm_DIR} can be set to the directory that contains this file.
.. code-block:: cmake
:caption: Loading |VTKm| configuration from an external CMake project.
find_package(VTKm REQUIRED)
.. didyouknow::
The CMake :cmake:command:`find_package` function also supports several features not discussed here including specifying a minimum or exact version of |VTKm| and turning off some of the status messages.
See the CMake documentation for more details.
.. index::
triple: CMake ; VTK-m package ; libraries
When you load the |VTKm| package in CMake, several libraries are defined.
Projects building with |VTKm| components should link against one or more of these libraries as appropriate, typically with the :cmake:command:`target_link_libraries` command.
.. code-block:: cmake
:caption: Linking |VTKm| code into an external program.
find_package(VTKm REQUIRED)
add_executable(myprog myprog.cxx)
target_link_libraries(myprog vtkm::filter)
Several library targets are provided, but most projects will need to link in one or more of the following.
..
Note that I am documenting the VTK-m targets as CMake variables. This is
because the Sphinx extension for the CMake domain that I am using currently
does not support documenting targets.
.. cmake:variable:: vtkm::cont
Contains the base objects used to control |VTKm|.
.. cmake:variable:: vtkm::filter
Contains |VTKm|'s pre-built filters.
Applications that are looking to use VTK-m filters will need to link to this library.
The filters are further broken up into several smaller library packages (such as :cmake:variable:`vtkm::filter_contour`, :cmake:variable`vtkm::filter_flow`, :cmake:variable:`vtkm::filter_field_transform`, and many more.
:cmake:variable:`vtkm::filter` is actually a meta library that links all of these filter libraries to a CMake target.
.. cmake:variable:: vtkm::io
Contains |VTKm|'s facilities for interacting with files.
For example, reading and writing png, NetBPM, and VTK files.
.. cmake:variable:: vtkm::rendering
Contains |VTKm|'s rendering components.
This library is only available if :cmake:variable:`VTKm_ENABLE_RENDERING` is set to true.
.. cmake:variable:: vtkm::source
Contains |VTKm|'s pre-built dataset generators suchas Wavelet, Tangle, and Oscillator.
Most applications will not need to link to this library.
.. didyouknow::
The "libraries" made available in the |VTKm| do more than add a library to the linker line.
These libraries are actually defined as external targets that establish several compiler flags, like include file directories.
Many CMake packages require you to set up other target options to compile correctly, but for |VTKm| it is sufficient to simply link against the library.
.. commonerrors::
Because the |VTKm| CMake libraries do more than set the link line, correcting the link libraries can do more than fix link problems.
For example, if you are getting compile errors about not finding |VTKm| header files, then you probably need to link to one of |VTKm|'s libraries to fix the problem rather than try to add the include directories yourself.
.. index::
triple: CMake; VTK-m package; variables
The following is a list of all the CMake variables defined when the \textcode{find_package} function completes.
.. cmake:variable:: VTKm_FOUND
Set to true if the |VTKm| CMake package is successfully loaded.
If :cmake:command:`find_package` was not called with the ``REQUIRED`` option, then this variable should be checked before attempting to use |VTKm|.
.. cmake:variable:: VTKm_VERSION
The version number of the loaded |VTKm| package.
This is in the form "major.minor".
.. cmake:variable:: VTKm_VERSION_FULL
The extended version number of the |VTKm| package including patch and in-between-release information.
This is in the form "major.minor.patch[.gitsha1]" where "gitsha" is only included if the source code is in between releases.
.. cmake:variable:: VTKm_VERSION_MAJOR
The major |VTKm| version number.
.. cmake:variable:: VTKm_VERSION_MINOR
The minor |VTKm| version number.
.. cmake:variable:: VTKm_VERSION_PATCH
The patch |VTKm| version number.
.. cmake:variable:: VTKm_ENABLE_CUDA
Set to true if |VTKm| was compiled for CUDA.
.. cmake:variable:: VTKm_ENABLE_Kokkos
Set to true if |VTKm| was compiled with Kokkos.
.. cmake:variable:: VTKm_ENABLE_OPENMP
Set to true if |VTKm| was compiled for OpenMP.
.. cmake:variable:: VTKm_ENABLE_TBB
Set to true if |VTKm| was compiled for TBB.
.. cmake:variable:: VTKm_ENABLE_RENDERING
Set to true if the |VTKm| rendering library was compiled.
.. cmake:variable:: VTKm_ENABLE_MPI
Set to true if |VTKm| was compiled with MPI support.
These package variables can be used to query whether optional components are supported before they are used in your CMake configuration.
.. code-block:: cmake
:caption: Using an optional component of |VTKm|.
find_package(VTKm REQUIRED)
if (NOT VTKm::ENABLE::RENDERING)
message(FATAL_ERROR "VTK-m must be built with rendering on.")
endif()
add_executable(myprog myprog.cxx)
target_link_libraries(myprog vtkm::cont vtkm::rendering)

@ -0,0 +1,21 @@
.. DO NOT EDIT!
.. Created by GuideExampleColorTables test.
.. |Black---Blue---White| image:: images/color-tables/Black---Blue---White.png
.. |Black-Body-Radiation| image:: images/color-tables/Black-Body-Radiation.png
.. |Blue---Green---Orange| image:: images/color-tables/Blue---Green---Orange.png
.. |Blue-to-Orange| image:: images/color-tables/Blue-to-Orange.png
.. |Cold-and-Hot| image:: images/color-tables/Cold-and-Hot.png
.. |Cool-to-Warm| image:: images/color-tables/Cool-to-Warm.png
.. |Cool-to-Warm-Extended| image:: images/color-tables/Cool-to-Warm-Extended.png
.. |Default| image:: images/color-tables/Default.png
.. |Gray-to-Red| image:: images/color-tables/Gray-to-Red.png
.. |Green| image:: images/color-tables/Green.png
.. |Inferno| image:: images/color-tables/Inferno.png
.. |Jet| image:: images/color-tables/Jet.png
.. |Plasma| image:: images/color-tables/Plasma.png
.. |Rainbow-Desaturated| image:: images/color-tables/Rainbow-Desaturated.png
.. |Rainbow-Uniform| image:: images/color-tables/Rainbow-Uniform.png
.. |Viridis| image:: images/color-tables/Viridis.png
.. |X-Ray| image:: images/color-tables/X-Ray.png
.. |Yellow---Gray---Blue| image:: images/color-tables/Yellow---Gray---Blue.png

103
docs/users-guide/conf.py Normal file

@ -0,0 +1,103 @@
##============================================================================
## 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.
##============================================================================
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = "The VTK-m User's Guide"
copyright = 'Kitware Inc., National Technology & Engineering Solutions of Sandia LLC, UT-Battelle LLC, Los Alamos National Security LLC'
author = 'Kenneth Moreland'
version = '@VTKm_VERSION_FULL@'
release = '@VTKm_VERSION_FULL@'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
# We provide some custom extensions in the _ext directory
import sys
sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@/_ext')
extensions = [
'sphinx.ext.autosectionlabel',
'sphinx.ext.mathjax',
'sphinx.ext.todo',
# Extension available from https://breathe.readthedocs.io/en/stable/
'breathe',
# Extension available from https://sphinx-themes.org/sample-sites/sphinx-rtd-theme/
# Can be installed with `pip install sphinx-rtd-theme`
'sphinx_rtd_theme',
# Extension available from https://github.com/scikit-build/moderncmakedomain
# Can be installed with `pip install sphinxcontrib-moderncmakedomain`
'sphinxcontrib.moderncmakedomain',
# Extensions included in the _ext directory.
'extract_examples',
'fullref',
'infoboxes',
]
# Note: there are some custom extensions at the bottom of this file.
todo_include_todos = @include_todos@
numfig = True
autosectionlabel_prefix_document = True
#templates_path = ['_templates']
exclude_patterns = ['CMakeFiles', '*.cmake', '.DS_Store']
primary_domain = 'cpp'
highlight_language = 'cpp'
numfig = True
numfig_format = {
'figure': 'Figure %s',
'table': 'Table %s',
'code-block': 'Example %s',
'section': '%s',
}
today_fmt = '%B %d, %Y'
rst_prolog = '''
.. |VTKm| replace:: VTKm
.. |Veclike| replace:: ``Vec``-like
.. |report-year| replace:: 2023
.. |report-number| replace:: ORNL/TM-2023/3182
'''
breathe_projects = { 'vtkm': '@doxygen_xml_output_dir@' }
breathe_default_project = 'vtkm'
example_directory = '@example_directory@'
example_command_comment = '////'
example_language = 'cpp'
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
#html_theme = 'alabaster'
#html_theme = 'sphinxdoc'
#html_theme = 'bizstyle'
#html_theme = 'classic'
html_theme = 'sphinx_rtd_theme'
#html_static_path = ['_static']
# -- Options for LaTeX output -------------------------------------------------
latex_toplevel_sectioning = 'part'

@ -0,0 +1,588 @@
==============================
Data Sets
==============================
.. index:: data set
A *data set*, implemented with the :class:`vtkm::cont::DataSet` class,
contains and manages the geometric data structures that |VTKm| operates on.
.. index::
single: cell set
single: field
single: coordinate system
.. doxygenclass:: vtkm::cont::DataSet
In addition to the base :class:`vtkm::cont::DataSet`, |VTKm| provides :class:`vtkm::cont::PartitionedDataSet` to represent data partitioned into multiple domains.
A :class:`vtkm::cont::PartitionedDataSet` is implemented as a collection of :class:`vtkm::cont::DataSet` objects.
Partitioned data sets are described later in :secref:`dataset:Partitioned Data Sets`.
------------------------------
Building Data Sets
------------------------------
.. index:: data set ; building
Before we go into detail on the cell sets, fields, and coordinate systems that make up a data set in |VTKm|, let us first discuss how to build a data set.
One simple way to build a data set is to load data from a file using the `vtkm::io` module.
Reading files is discussed in detail in :chapref:`io:File I/O`.
This section describes building data sets of different types using a set of
classes named `DataSetBuilder*`, which provide a convenience layer
on top of :class:`vtkm::cont::DataSet` to make it easier to create data sets.
.. didyouknow::
To simplify the introduction of :class:`vtkm::cont::DataSet` objects, this section uses the simplest mechanisms.
In many cases this involves loading data in a `std::vector` and passing that to |VTKm|, which usually causes the data to be copied.
This is not the most efficient method to load data into |VTKm|.
Although it is sufficient for small data or data that come from a "slow" source, such as a file, it might be a bottleneck for large data generated by another library.
It is possible to adapt |VTKm|'s :class:`vtkm::cont::DataSet` to externally defined data.
This is done by wrapping existing data into what is called `ArrayHandle`, but this is a more advanced topic that will not be addressed in this chapter.
`ArrayHandle` objects are introduced in :chapref:`basic-array-handles:Basic Array Handles` and more adaptive techniques are described in later chapters.
Creating Uniform Grids
==============================
.. index::
single: uniform grid
single: regular grid
single: image
Uniform grids are meshes that have a regular array structure with points uniformly spaced parallel to the axes.
Uniform grids are also sometimes called regular grids or images.
The :class:`vtkm::cont::DataSetBuilderUniform` class can be used to easily create 2- or 3-dimensional uniform grids.
:class:`vtkm::cont::DataSetBuilderUniform` has several versions of a method named :func:`vtkm::cont::DataSetBuilderUniform::Create` that takes the number of points in each dimension, the origin, and the spacing.
The origin is the location of the first point of the data (in the lower left corner), and the spacing is the distance between points in the x, y, and z directions.
.. doxygenclass:: vtkm::cont::DataSetBuilderUniform
:members:
The following example creates a :class:`vtkm::cont::DataSet` containing a uniform grid of :math:`101 \times 101 \times 26` points.
.. load-example:: CreateUniformGrid
:file: GuideExampleDataSetCreation.cxx
:caption: Creating a uniform grid.}{.cxx}
If not specified, the origin will be at the coordinates :math:`(0,0,0)` and the spacing will be :math:`1` in each direction.
Thus, in the previous example the width, height, and depth of the mesh in physical space will be :math:`100`, :math:`100`, and :math`25`, respectively, and the mesh will be centered at :math:`(50, 50, 12.5)`.
Let us say we actually want a mesh of the same dimensions, but we want the :math:`z` direction to be stretched out so that the mesh will be the same size in each direction, and we want the mesh centered at the origin.
.. load-example:: CreateUniformGridCustomOriginSpacing
:file: GuideExampleDataSetCreation.cxx
:caption: Creating a uniform grid with custom origin and spacing.
Creating Rectilinear Grids
==============================
.. index:: rectilinear grid
A rectilinear grid is similar to a uniform grid except that a rectilinear grid can adjust the spacing between adjacent grid points.
This allows the rectilinear grid to have tighter sampling in some areas of space, but the points are still constrained to be aligned with the axes and each other.
The irregular spacing of a rectilinear grid is specified by providing a separate array each for the x, y, and z coordinates.
The :class:`vtkm::cont::DataSetBuilderRectilinear` class can be used to easily create
2- or 3-dimensional rectilinear grids.
:class:`vtkm::cont::DataSetBuilderRectilinear` has several versions of a method
named :func:`vtkm::cont::DataSetBuilderRectilinear::Create` that takes these coordinate arrays and builds a
:class:`vtkm::cont::DataSet` out of them. The arrays can be supplied as either
standard C arrays or as `std::vector` objects, in which case the
data in the arrays are copied into the :class:`vtkm::cont::DataSet`. These
arrays can also be passed as :class:`vtkm::cont::ArrayHandle` objects (introduced later in this book), in which
case the data are shallow copied.
.. doxygenclass:: vtkm::cont::DataSetBuilderRectilinear
:members:
The following example creates a :class:`vtkm::cont::DataSet` containing a rectilinear
grid with :math:`201 \times 201 \times 101` points with different irregular
spacing along each axis.
.. load-example:: CreateRectilinearGrid
:file: GuideExampleDataSetCreation.cxx
:caption: Creating a rectilinear grid.
Creating Explicit Meshes
==============================
.. index::
single: explicit mesh
single: unstructured grid
An explicit mesh is an arbitrary collection of cells with arbitrary connections.
It can have multiple different types of cells.
Explicit meshes are also known as unstructured grids.
Explicit meshes can contain cells of different shapes.
The shapes that |VTKm| currently supports are listed in :numref:`fig:CreateExplicitMeshesCellShapes`.
Each shape is identified using either a numeric identifier, provided by |VTKm| with identifiers of the form ``vtkm::CELL_SHAPE_*`` or special tag structures of the form ``vtkm::CellSetTag*``.
Cell shapes are discussed in detail in :chapref:`working-with-cells:Working with Cells`.
.. figure:: images/CellConnections.png
:width: 100%
:name: fig:CreateExplicitMeshesCellShapes
Basic Cell Shapes.
.. todo:: Add ``vtkm::CellShapeTagPolyLine`` to this figure.
..
.. |CellConnectionsVertex| image:: images/CellConnectionsVertex.png
.. |CellConnectionsLine| image:: images/CellConnectionsLine.png
.. |CellConnectionsPolyLine| image:: images/CellConnectionsPolyLine.png
.. |CellConnectionsTriangle| image:: images/CellConnectionsTriangle.png
.. |CellConnectionsPolygon| image:: images/CellConnectionsPolygon.png
.. |CellConnectionsQuadrilateral| image:: images/CellConnectionsQuadrilateral.png
.. |CellConnectionsTetrahedron| image:: images/CellConnectionsTetrahedron.png
.. |CellConnectionsHexahedron| image:: images/CellConnectionsHexahedron.png
.. |CellConnectionsWedge| image:: images/CellConnectionsWedge.png
.. |CellConnectionsPyramid| image:: images/CellConnectionsPyramid.png
.. table:: Basic Cell Shapes
:name: ExplicitCellShapes
:width: 100%
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
| :enumerator:`vtkm::CELL_SHAPE_VERTEX` | :enumerator:`vtkm::CELL_SHAPE_Line` | :enumerator:`vtkm::CELL_SHAPE_POLY_LINE` |
| :struct:`vtkm::CellShapeTagVertex` | :struct:`vtkm::CellShapeTagLine` | :struct:`vtkm::CellShapeTagPolyLine` |
| |CellConnectionsVertex| | |CellConnectionsLine| | |CellConnectionsPolyLine| |
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
| :enumerator:`vtkm::CELL_SHAPE_TRIANGLE` | :enumerator:`vtkm::CELL_SHAPE_POLYGON` | :enumerator:`vtkm::CELL_SHAPE_QUADRILATERAL` |
| :struct:`vtkm::CellShapeTagTriangle` | :struct:`vtkm::CellShapeTagPolygon` | :struct:`vtkm::CellShapeTagQuadrilateral` |
| |CellConnectionsTriangle| | |CellConnectionsPolygon| | |CellConnectionsQuadrilateral| |
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
| :enumerator:`vtkm::CELL_SHAPE_TETRAHEDRON` | :enumerator:`vtkm::CELL_SHAPE_HEXAHEDRON` | :enumerator:`vtkm::CELL_SHAPE_WEDGE` |
| :struct:`vtkm::CellShapeTagTetrahedron` | :struct:`vtkm::CellShapeTagHexahedron` | :struct:`vtkm::CellShapeTagWedge` |
| |CellConnectionsTetrahedron| | |CellConnectionsHexahedron| | |CellConnectionsWedge| |
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
| | :enumerator:`vtkm::CELL_SHAPE_PYRAMID` | |
| | :struct:`vtkm::CellShapeTagPyramid` | |
| | |CellConnectionsPyramid| | |
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
.. figure:: images/ExplicitCellConnections.png
:width: 100%
:name: fig:ExplicitMesh
An example explicit mesh.
The cells of an explicit mesh are defined with the following 3 arrays, which are depicted graphically in :numref:`fig:ExplicitMesh`.
.. index:: explicit mesh ; shapes
Shapes
An array of ids identifying the shape of the cell.
Each value is a :type:`vtkm::UInt8` and should be set to one of the ``vtkm::CELL_SHAPE_*`` constants.
The shapes and their identifiers are shown in :numref:`fig:CreateExplicitMeshesCellShapes`.
The size of this array is equal to the number of cells in the set.
.. index:: explicit mesh ; connectivity
Connectivity
An array that lists all the points that comprise each cell.
Each entry in the array is a :type:`vtkm::Id` giving the point id associated with a vertex of a cell.
The points for each cell are given in a prescribed order for each shape, which is also shown in :numref:`fig:CreateExplicitMeshesCellShapes`.
The point indices are stored consecutively from the first cell to the last.
.. index:: explicit mesh ; offsets
Offsets
An array of :type:`vtkm::Id`'s pointing to the index in the connectivity array where the points for a particular cell starts.
The size of this array is equal to the number of cells in the set plus 1.
The first entry is expected to be 0 (since the connectivity of the first cell is at the start of the connectivity array).
The last entry, which does not correspond to any cell, should be the size of the connectivity array.
One important item that is missing from this list of arrays is a count of the number of indices associated with each cell.
This is not explicitly represented in |VTKm|'s mesh structure because it can be implicitly derived from the offsets array by subtracting consecutive entries.
However, it is usually the case when building an explicit mesh that you will have an array of these counts rather than the offsets.
It is for this reason that |VTKm| contains mechanisms to build an explicit data set with a "num indices" arrays rather than an offsets array.
The :class:`vtkm::cont::DataSetBuilderExplicit` class can be used to create data sets with explicit meshes.
:class:`vtkm::cont::DataSetBuilderExplicit` has several versions of a method named :func:`vtkm::cont::DataSetBuilderExplicit::Create`.
Generally, these methods take the shapes, number of indices, and connectivity arrays as well as an array of point coordinates.
.. doxygenclass:: vtkm::cont::DataSetBuilderExplicit
:members:
The following example creates a mesh like the one shown in
:numref:`fig:ExplicitMesh`.
.. load-example:: CreateExplicitGrid
:file: GuideExampleDataSetCreation.cxx
:caption: Creating an explicit mesh with :class:`vtkm::cont::DataSetBuilderExplicit`.
Often it is awkward to build your own arrays and then pass them to :class:`vtkm::cont::DataSetBuilderExplicit`.
There also exists an alternate builder class named :class:`vtkm::cont::DataSetBuilderExplicitIterative` that allows you to specify each cell and point one at a time rather than all at once.
This is done by calling one of the versions of :func:`vtkm::cont::DataSetBuilderExplicitIterative::AddPoint` and one of the versions of :func:`vtkm::cont::DataSetBuilderExplicitIterative::AddCell` for each point and cell, respectively.
.. doxygenclass:: vtkm::cont::DataSetBuilderExplicitIterative
:members:
The next example also builds the mesh shown in :numref:`fig:ExplicitMesh` except this time using :class:`vtkm::cont::DataSetBuilderExplicitIterative`.
.. load-example:: CreateExplicitGridIterative
:file: GuideExampleDataSetCreation.cxx
:caption: Creating an explicit mesh with :class:`vtkm::cont::DataSetBuilderExplicitIterative`.
Add Fields
==============================
In addition to creating the geometric structure of a data set, it is usually important to add fields to the data.
Fields describe numerical data associated with the topological elements in a cell.
They often represent a physical quantity (such as temperature, mass, or volume fraction) but can also represent other information (such as indices or classifications).
The easiest way to define fields in a data set is to use the :func:`vtkm::cont::DataSet::AddPointField` and :func:`vtkm::cont::DataSet::AddCellField` methods.
Each of these methods take a requisite field name and the array with with field data.
Both :func:`vtkm::cont::DataSet::AddPointField` and :func:`vtkm::cont::DataSet::AddCellField` are overloaded to accept arrays of data in different structures.
Field arrays can be passed as standard C arrays or as ``std::vector``'s, in which case the data are copied.
Field arrays can also be passed in a ``ArrayHandle`` (introduced later in this book), in which case the data are not copied.
.. doxygenfunction:: vtkm::cont::DataSet::AddPointField(const std::string&, const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::DataSet::AddPointField(const std::string&, const std::vector<T>&)
.. doxygenfunction:: vtkm::cont::DataSet::AddPointField(const std::string&, const T*, const vtkm::Id&)
.. doxygenfunction:: vtkm::cont::DataSet::AddCellField(const std::string&, const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::DataSet::AddCellField(const std::string&, const std::vector<T>&)
.. doxygenfunction:: vtkm::cont::DataSet::AddCellField(const std::string&, const T*, const vtkm::Id&)
The following (somewhat contrived) example defines fields for a uniform grid that identify which points and cells are on the boundary of the mesh.
.. load-example:: AddFieldData
:file: GuideExampleDataSetCreation.cxx
:caption: Adding fields to a :class:`vtkm::cont::DataSet`.
------------------------------
Cell Sets
------------------------------
.. index:: cell set
.. index:: data set ; cell set
.. index::
triple: cell; shape; point
triple: cell; shape; edge
triple: cell; shape; face
A cell set determines the topological structure of the data in a data set.
.. doxygenclass:: vtkm::cont::CellSet
:members:
3D cells are made up of *points*, *edges*, and *faces*.
(2D cells have only points and edges, and 1D cells have only points.)
:numref:`fig:CellTopology` shows the relationship between a cell's shape and these topological elements.
The arrangement of these points, edges, and faces is defined by the *shape* of the cell, which prescribes a specific ordering of each.
The basic cell shapes provided by |VTKm| are discussed in detail in :chapref:`working-with-cells:Working with Cells`.
.. todo:: Add cell shape reference above.
.. figure:: images/CellConstituents.png
:width: 50%
:name: fig:CellTopology
The relationship between a cell shape and its topological elements (points, edges, and faces).
There are multiple ways to express the connections of a cell set, each with
different benefits and restrictions. These different cell set types are
managed by different cell set classes in |VTKm|. All |VTKm| cell set classes
inherit from :class:`vtkm::cont::CellSet`. The two basic types of cell sets are
structured and explicit, and there are several variations of these types.
Structured Cell Sets
==============================
.. index::
single: cell set; structured
single: structured cell set
.. doxygenclass:: vtkm::cont::CellSetStructured
:members:
The number of points in a :class:`vtkm::cont::CellSetStructured` is implicitly :math:`i \times j \times k` and the number of cells is implicitly :math:`(i-1) \times (j-1) \times (k-1)` (for 3D grids).
:numref:`fig:CellSetStructured` demonstrates this arrangement.
.. figure:: images/StructuredCellSet.png
:width: 100%
:name: fig:CellSetStructured
The arrangement of points and cells in a 3D structured grid.
The big advantage of using :class:`vtkm::cont::CellSetStructured` to define a cell set is that it is very space efficient because the entire topology can be defined by the three integers specifying the dimensions.
Also, algorithms can be optimized for :class:`vtkm::cont::CellSetStructured`'s regular nature.
However, :class:`vtkm::cont::CellSetStructured`'s strictly regular grid also limits its applicability.
A structured cell set can only be a dense grid of lines, quadrilaterals, or hexahedra.
It cannot represent irregular data well.
Many data models in other software packages, such as the one for VTK, make a distinction between uniform, rectilinear, and curvilinear grids.
|VTKm|'s cell sets do not.
All three of these grid types are represented by :class:`vtkm::cont::CellSetStructured`.
This is because in a |VTKm| data set the cell set and the coordinate system are defined independently and used interchangeably.
A structured cell set with uniform point coordinates makes a uniform grid.
A structured cell set with point coordinates defined irregularly along coordinate axes makes a rectilinear grid.
And a structured cell set with arbitrary point coordinates makes a curvilinear grid.
The point coordinates are defined by the data set's coordinate system, which is discussed in :secref:`dataset:Coordinate Systems`.
Explicit Cell Sets
==============================
.. index::
single: cell set; explicit
single: explicit cell set
.. doxygenclass:: vtkm::cont::CellSetExplicit
:members:
The types of cell sets are listed in :numref:`fig:ExplicitCellSetShapes`.
.. figure:: images/CellConnections.png
:width: 100%
:name: fig:ExplicitCellSetShapes
Basic Cell Shapes in a :class:`vtkm::cont::CellSetExplicit`.
An explicit cell set is defined with a minimum of three arrays.
The first array identifies the shape of each cell.
(Identifiers for cell shapes are shown in :numref:`fig:ExplicitCellSetShapes`.)
The second array has a sequence of point indices that make up each cell.
The third array identifies an offset into the second array where the point indices for each cell is found plus an extra entry at the end set to the size of the second array.
:numref:`fig:CellSetExplicit` shows a simple example of an explicit cell set.
.. figure:: images/ExplicitCellConnections.png
:width: 100%
:name: fig:CellSetExplicit
Example of cells in a :class:`vtkm::cont::CellSetExplicit` and the arrays that define them.
An explicit cell set can also identify the number of indices defined for each cell by subtracting consecutive entries in the offsets array.
It is often the case when creating a :class:`vtkm::cont::CellSetExplicit` that you have an array containing the number of indices rather than the offsets.
Such an array can be converted to an offsets array that can be used with :class:`vtkm::cont::CellSetExplicit` by using the :func:`vtkm::cont::ConvertNumComponentsToOffsets` convenience function.
.. doxygenfunction:: vtkm::cont::ConvertNumComponentsToOffsets(const vtkm::cont::UnknownArrayHandle&, vtkm::cont::ArrayHandle<vtkm::Id>&, vtkm::Id&, vtkm::cont::DeviceAdapterId)
:class:`vtkm::cont::CellSetExplicit` is a powerful representation for a cell set
because it can represent an arbitrary collection of cells. However, because
all connections must be explicitly defined,
:class:`vtkm::cont::CellSetExplicit` requires a significant amount of memory to
represent the topology.
.. index::
single: cell set; single type
single: explicit cell set; single type
single: single type cell set
An important specialization of an explicit cell set is
:class:`vtkm::cont::CellSetSingleType`.
.. doxygenclass:: vtkm::cont::CellSetSingleType
:members:
Cell Set Permutations
==============================
.. index::
single: cell set; permutation
single: permutation cell set
To rearrange, and possibly subsample, cells in a ``CellSet``, use :type:`vtkm::cont::CellSetPermutation` to define a new set without copying.
.. doxygenclass:: vtkm::cont::CellSetPermutation
:members:
.. didyouknow::
Although :class:`vtkm::cont::CellSetPermutation` can mask cells, it cannot mask points.
All points from the original cell set are available in the permuted cell set regardless of whether they are used.
The following example uses :class:`vtkm::cont::CellSetPermutation` with a counting array to expose every tenth cell.
This provides a simple way to subsample a data set.
.. load-example:: CreateCellSetPermutation
:file: GuideExampleDataSetCreation.cxx
:caption: Subsampling a data set with :class:`vtkm::cont::CellSetPermutation`.
Cell Set Extrude
==============================
.. doxygenclass:: vtkm::cont::CellSetExtrude
:members:
.. figure:: images/ExtrudedCellSet.png
:width: 100%
:name: fig:CellSetExtruded
An example of an extruded wedge from XZ-plane coordinates.
Six wedges are extracted from three XZ-plane points.
The extruded mesh is advantageous because it is represented on-the-fly as required, so no additional memory is required.
In contrast other forms of cell sets, such as :class:`vtkm::cont::CellSetExplicit`, need to be explicitly constructed by replicating the vertices and cells.
:numref:`fig:CellSetExtruded` shows an example of six wedges extruded from three 2-dimensional coordinates.
Unknown Cell Sets
==============================
Each of the aforementioned cell set types are represented by a different class.
A :class:`vtkm::cont::DataSet` object must hold one of these cell set objects that represent the cell structure.
The actual object used is not determined until run time.
The :class:`vtkm::cont::DataSet` object manages the cell set object with :class:`vtkm::cont::UnknownCellSet`.
When you call :func:`vtkm::cont::DataSet::GetCellSet`, it returns a :class:`vtkm::cont::UnknownCellSet`.
The :class:`vtkm::cont::UnknownCellSet` object provides mechanisms to query the cell set, identify its type, and cast it to one of the concrete ``CellSet`` types.
See Chapter \ref{chap:UnknownCellSet} for details on working with :class:`vtkm::cont::UnknownCellSet`.
.. todo:: Add previous reference to UnknownCellSet chapter.
------------------------------
Fields
------------------------------
.. index::
single: field
single: data set; field
A field on a data set provides a value on every point in space on the mesh.
Fields are often used to describe physical properties such as pressure, temperature, mass, velocity, and much more.
Fields are represented in a |VTKm| data set as an array where each value is associated with a particular element type of a mesh (such as points or cells).
This association of field values to mesh elements and the structure of the cell set determines how the field is interpolated throughout the space of the mesh.
Fields are manged by the :class:`vtkm::cont::Field` class.
.. doxygenclass:: vtkm::cont::Field
Fields are identified by a simple name string.
.. doxygenfunction:: vtkm::cont::Field::GetName
The :class:`vtkm::cont::Field` object internally holds a reference to an array in a type-agnostic way.
Filters and other |VTKm| units will determine the type of the array and pull it out of the :class:`vtkm::cont::Field`.
.. doxygenfunction:: vtkm::cont::Field::GetData() const
The field data is associated with a particular type of element of a mesh such as points, cells, or the whole mesh.
.. doxygenfunction:: vtkm::cont::Field::GetAssociation
Associations are identified by the :enum:`vtkm::cont::Field::Association` enumeration.
.. doxygenenum:: vtkm::cont::Field::Association
The :class:`vtkm::cont::Field` class also has several convenience methods for querying the association.
.. doxygenfunction:: vtkm::cont::Field::IsPointField
.. doxygenfunction:: vtkm::cont::Field::IsCellField
.. doxygenfunction:: vtkm::cont::Field::IsWholeDataSetField
.. doxygenfunction:: vtkm::cont::Field::IsPartitionsField
.. doxygenfunction:: vtkm::cont::Field::IsGlobalField
.. index:: double: range; field
:class:`vtkm::cont::Field` has a convenience method named :func:`vtkm::cont::Field::GetRange` that finds the range of values stored in the field array.
.. doxygenfunction:: vtkm::cont::Field::GetRange() const
Details on how to get data from a :class:`vtkm::cont::ArrayHandle` them is given in Chapter \ref{chap:AccessingAllocatingArrays}.
.. todo:: Fix above reference to array handle chapter.
------------------------------
Coordinate Systems
------------------------------
.. index::
single: coordinate system
single: data set; coordinate system
A coordinate system determines the location of a mesh's elements in space.
The spatial location is described by providing a 3D vector at each point that gives the coordinates there.
The point coordinates can then be interpolated throughout the mesh.
.. doxygenclass:: vtkm::cont::CoordinateSystem
In addition to all the methods provided by the :class:`vtkm::cont::Field` superclass, the :class:`vtkm::cont::CoordinateSystem` also provides a :func:`vtkm::cont::CoordinateSystem::GetBounds` convenience method that returns a :class:`vtkm::Bounds` object giving the spatial bounds of the coordinate system.
.. doxygenfunction:: vtkm::cont::CoordinateSystem::GetBounds
It is typical for a :class:`vtkm::cont::DataSet` to have one coordinate system defined, but it is possible to define multiple coordinate systems.
This is helpful when there are multiple ways to express coordinates.
For example, positions in geographic may be expressed as Cartesian coordinates or as latitude-longitude coordinates.
Both are valid and useful in different ways.
It is also valid to have a :class:`vtkm::cont::DataSet` with no coordinate system.
This is useful when the structure is not rooted in physical space.
For example, if the cell set is representing a graph structure, there might not be any physical space that has meaning for the graph.
------------------------------
Partitioned Data Sets
------------------------------
.. index::
single: partitioned data set
single: data set; partitioned
.. doxygenclass:: vtkm::cont::PartitionedDataSet
:members:
The following example creates a :class:`vtkm::cont::PartitionedDataSet` containing two uniform grid data sets.
.. load-example:: CreatePartitionedDataSet
:file: GuideExampleDataSetCreation.cxx
:caption: Creating a :class:`vtkm::cont::PartitionedDataSet`.
It is always possible to retrieve the independent blocks in a :class:`vtkm::cont::PartitionedDataSet`, from which you can iterate and get information about the data.
However, |VTKm| provides several helper functions to collect metadata information about the collection as a whole.
.. doxygenfunction:: vtkm::cont::BoundsCompute(const vtkm::cont::DataSet&, vtkm::Id)
.. doxygenfunction:: vtkm::cont::BoundsCompute(const vtkm::cont::PartitionedDataSet&, vtkm::Id)
.. doxygenfunction:: vtkm::cont::BoundsCompute(const vtkm::cont::DataSet&, const std::string&)
.. doxygenfunction:: vtkm::cont::BoundsCompute(const vtkm::cont::PartitionedDataSet&, const std::string&)
.. doxygenfunction:: vtkm::cont::BoundsGlobalCompute(const vtkm::cont::DataSet&, vtkm::Id)
.. doxygenfunction:: vtkm::cont::BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet&, vtkm::Id)
.. doxygenfunction:: vtkm::cont::BoundsGlobalCompute(const vtkm::cont::DataSet&, const std::string&)
.. doxygenfunction:: vtkm::cont::BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet&, const std::string&)
.. doxygenfunction:: vtkm::cont::FieldRangeCompute(const vtkm::cont::DataSet&, const std::string&, vtkm::cont::Field::Association)
.. doxygenfunction:: vtkm::cont::FieldRangeCompute(const vtkm::cont::PartitionedDataSet&, const std::string&, vtkm::cont::Field::Association)
.. doxygenfunction:: vtkm::cont::FieldRangeGlobalCompute(const vtkm::cont::DataSet&, const std::string&, vtkm::cont::Field::Association)
.. doxygenfunction:: vtkm::cont::FieldRangeGlobalCompute(const vtkm::cont::PartitionedDataSet&, const std::string&, vtkm::cont::Field::Association)
The following example illustrates a spatial bounds query and a field range query on a :class:`vtkm::cont::PartitionedDataSet`.
.. load-example:: QueryPartitionedDataSet
:file: GuideExampleDataSetCreation.cxx
:caption: Queries on a :class:`vtkm::cont::PartitionedDataSet`.
.. didyouknow::
The aforementioned functions for querying a :class:`vtkm::cont::PartitionedDataSet` object also work on :class:`vtkm::cont::DataSet` objects.
This is particularly useful with the :func:`vtkm::cont::BoundsGlobalCompute` and :func:`vtkm::cont::FieldRangeGlobalCompute` functions to manage distributed parallel objects.
Filters can be executed on :class:`vtkm::cont::PartitionedDataSet` objects in a similar way they are executed on :class:`vtkm::cont::DataSet` objects.
In both cases, the :func:`vtkm::cont::Filter::Execute` method is called on the filter giving data object as an argument.
.. load-example:: FilterPartitionedDataSet
:file: GuideExampleDataSetCreation.cxx
:caption: Applying a filter to multi block data.

@ -0,0 +1,116 @@
==============================
Error Handling
==============================
|VTKm| contains several mechanisms for checking and reporting error conditions.
------------------------------
Runtime Error Exceptions
------------------------------
.. index::
double: errors; control environment
|VTKm| uses exceptions to report errors.
All exceptions thrown by |VTKm| will be a subclass of :class:`vtkm::cont::Error`.
For simple error reporting, it is possible to simply catch a :class:`vtkm::cont::Error` and report the error message string reported by the :func:`vtkm::cont::Error::GetMessage` method.
.. load-example:: CatchingErrors
:file: GuideExampleErrorHandling.cxx
:caption: Simple error reporting.
.. doxygenclass:: vtkm::cont::Error
:members:
There are several subclasses to :class:`vtkm::cont::Error`.
The specific subclass gives an indication of the type of error that occurred when the exception was thrown.
Catching one of these subclasses may help a program better recover from errors.
.. doxygenclass:: vtkm::cont::ErrorBadAllocation
:members:
.. doxygenclass:: vtkm::cont::ErrorBadDevice
:members:
.. doxygenclass:: vtkm::cont::ErrorBadType
:members:
.. doxygenclass:: vtkm::cont::ErrorBadValue
:members:
.. doxygenclass:: vtkm::cont::ErrorExecution
:members:
.. doxygenclass:: vtkm::cont::ErrorFilterExecution
:members:
.. doxygenclass:: vtkm::cont::ErrorInternal
:members:
.. doxygenclass:: vtkm::cont::ErrorUserAbort
:members:
.. doxygenclass:: vtkm::io::ErrorIO
:members:
------------------------------
Asserting Conditions
------------------------------
.. index::
double: errors; assert
In addition to the aforementioned error signaling, the ``vtkm/Assert.h`` header file defines a macro named :c:macro:`VTKM_ASSERT`.
This macro behaves the same as the POSIX :c:macro:`assert` macro.
It takes a single argument that is a condition that is expected to be true.
If it is not true, the program is halted and a message is printed.
Asserts are useful debugging tools to ensure that software is behaving and being used as expected.
.. doxygendefine:: VTKM_ASSERT
.. load-example:: Assert
:file: GuideExampleErrorHandling.cxx
:caption: Using :c:macro:`VTKM_ASSERT`.
.. didyouknow::
Like the POSIX :c:macro:`assert`, if the :c:macro:`NDEBUG` macro is defined, then :c:macro:`VTKM_ASSERT` will become an empty expression.
Typically :c:macro:`NDEBUG` is defined with a compiler flag (like ``-DNDEBUG``) for release builds to better optimize the code.
CMake will automatically add this flag for release builds.
.. commonerrors::
A helpful warning provided by many compilers alerts you of unused variables.
(This warning is commonly enabled on |VTKm| regression test nightly builds.)
If a function argument is used only in a :c:macro:`VTKM_ASSERT`, then it will be required for debug builds and be unused in release builds.
To get around this problem, add a statement to the function of the form ``(void)variableName;``.
This statement will have no effect on the code generated but will suppress the warning for release builds.
------------------------------
Compile Time Checks
------------------------------
.. index::
single: assert; static
single: static assert
Because |VTKm| makes heavy use of C++ templates, it is possible that these templates could be used with inappropriate types in the arguments.
Using an unexpected type in a template can lead to very confusing errors, so it is better to catch such problems as early as possible.
The :c:macro:`VTKM_STATIC_ASSERT` macro, defined in ``vtkm/StaticAssert.h`` makes this possible.
This macro takes a constant expression that can be evaluated at compile time and verifies that the result is true.
In the following example, :c:macro:`VTKM_STATIC_ASSERT` and its sister macro :c:macro:`VTKM_STATIC_ASSERT_MSG`, which allows you to give a descriptive message for the failure, are used to implement checks on a templated function that is designed to work on any scalar type that is represented by 32 or more bits.
.. load-example:: StaticAssert
:file: GuideExampleErrorHandling.cxx
:caption: Using :c:macro:`VTKM_STATIC_ASSERT`.
.. didyouknow::
In addition to the several trait template classes provided by |VTKm| to introspect C++ types, the C++ standard ``type_traits`` header file contains several helpful templates for general queries on types.
:numref:`ex:StaticAssert` demonstrates the use of one such template: ``std::is_same``.
.. commonerrors::
Many templates used to introspect types resolve to the tags ``std::true_type`` and ``std::false_type`` rather than the constant values ``true`` and ``false`` that :c:macro:`VTKM_STATIC_ASSERT` expects.
The ``std::true_type`` and ``std::false_type`` tags can be converted to the Boolean literal by adding ``::value`` to the end of them.
Failing to do so will cause :c:macro:`VTKM_STATIC_ASSERT` to behave incorrectly.
:numref:`ex:StaticAssert` demonstrates getting the Boolean literal from the result of ``std::is_same``.

@ -0,0 +1,17 @@
---
# This configuration requires clang-format 3.8 or higher.
BasedOnStyle: Mozilla
AlignAfterOpenBracket: Align
AlignOperands: false
AlwaysBreakAfterReturnType: None
AlwaysBreakAfterDefinitionReturnType: None
BreakBeforeBraces: Allman
BinPackArguments: false
BinPackParameters: false
ColumnLimit: 89
MaxEmptyLinesToKeep: 4
Standard: Cpp11
# This requires clang-format 4.0 (at least).
#FixNamespaceComments: true
ReflowComments: false
...

@ -0,0 +1,95 @@
##============================================================================
## 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.
##============================================================================
set(examples
GuideExampleArrayHandle.cxx
GuideExampleCellShapes.cxx
GuideExampleColorTables.cxx
GuideExampleCoreDataTypes.cxx
GuideExampleEnvironmentModifierMacros.cxx
GuideExampleInitialization.cxx
GuideExampleIO.cxx
GuideExampleLists.cxx
GuideExampleMatrix.cxx
GuideExampleNewtonsMethod.cxx
GuideExampleProvidedFilters.cxx
GuideExampleRendering.cxx
GuideExampleRuntimeDeviceTracker.cxx
GuideExampleTimer.cxx
GuideExampleTraits.cxx
GuideExampleTuple.cxx
)
set(examples_device
GuideExampleCellEdgesFaces.cxx
GuideExampleCellLocator.cxx
GuideExampleCellOperations.cxx
GuideExampleDataSetCreation.cxx
GuideExampleErrorHandling.cxx
GuideExampleFilterDataSetWithField.cxx
GuideExampleGenerateMeshConstantShape.cxx
GuideExampleSimpleAlgorithm.cxx
GuideExampleUseWorkletMapField.cxx
GuideExampleUseWorkletPointNeighborhood.cxx
GuideExampleUseWorkletReduceByKey.cxx
GuideExampleUseWorkletVisitCellsWithPoints.cxx
GuideExampleUseWorkletVisitPointsWithCells.cxx
)
set(extra_libs)
vtkm_find_gl(OPTIONAL GL GLUT)
if(TARGET GLUT::GLUT)
list(APPEND examples
GuideExampleRenderingInteractive.cxx
)
list(APPEND extra_libs OpenGL::GL GLUT::GLUT)
else()
message("Not building OpenGL tutorial examples because GL/GLUT not found.")
endif()
vtkm_unit_tests(
SOURCES ${examples}
DEVICE_SOURCES ${examples_device}
LIBRARIES ${extra_libs}
TEST_ARGS "--no-interaction"
)
# Special example that is an encapsulated program
# VTKm examples expects vtkm libraries to be namespaced with the prefix vtkm::.
# However as the examples are also built as just another part of the VTK-m code
# those prefix are not added to the targets (This happens during the
# installation). To workaround this issue here, we create IMPORTED libs linking
# to the vtkm libraries used by the examples with expected the vtkm:: prefix.
vtkm_module_get_list(module_list)
foreach(tgt IN LISTS module_list)
if(TARGET ${tgt})
# The reason of creating this phony IMPORTED libraries instead of making
# ALIAS libraries is that ALIAS libraries are GLOBAL whereas IMPORTED are
# local at the directory level where they are created. We do not want these
# phony targets to be visible outside of the example directory.
vtkm_target_mangle(tgt_name_mangled ${tgt})
add_library("vtkm::${tgt_name_mangled}" INTERFACE IMPORTED)
target_link_libraries("vtkm::${tgt_name_mangled}" INTERFACE ${tgt})
endif()
endforeach()
add_library(vtkm::filter INTERFACE IMPORTED)
target_link_libraries(vtkm::filter INTERFACE vtkm_filter)
#add the directory that contains the VTK-m config file to the cmake
#path so that our examples can find VTK-m
set(CMAKE_PREFIX_PATH ${VTKm_BINARY_DIR}/${VTKm_INSTALL_CONFIG_DIR})
include(VTKmQuickStart.cmake)
set_target_properties(VTKmQuickStart
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH}
)
add_test(NAME VTKmQuickStart
COMMAND VTKmQuickStart ${VTKm_SOURCE_DIR}/data/data/unstructured/cow.vtk
)

@ -0,0 +1,538 @@
//============================================================================
// 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.
//============================================================================
#define VTKM_NO_ERROR_ON_MIXED_CUDA_CXX_TAG
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/cont/testing/Testing.h>
#include <algorithm>
#include <vector>
namespace
{
template<typename T>
vtkm::Float32 TestValue(T index)
{
return static_cast<vtkm::Float32>(1 + 0.001 * index);
}
void CheckArrayValues(const vtkm::cont::ArrayHandle<vtkm::Float32>& array,
vtkm::Float32 factor = 1)
{
// So far all the examples are using 50 entries. Could change.
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 50, "Wrong number of values");
for (vtkm::Id index = 0; index < array.GetNumberOfValues(); index++)
{
VTKM_TEST_ASSERT(
test_equal(array.ReadPortal().Get(index), TestValue(index) * factor),
"Bad data value.");
}
}
////
//// BEGIN-EXAMPLE ArrayHandleParameterTemplate
////
template<typename T, typename Storage>
void Foo(const vtkm::cont::ArrayHandle<T, Storage>& array)
{
////
//// END-EXAMPLE ArrayHandleParameterTemplate
////
(void)array;
}
////
//// BEGIN-EXAMPLE ArrayHandleFullTemplate
////
template<typename ArrayType>
void Bar(const ArrayType& array)
{
VTKM_IS_ARRAY_HANDLE(ArrayType);
////
//// END-EXAMPLE ArrayHandleFullTemplate
////
(void)array;
}
void BasicConstruction()
{
////
//// BEGIN-EXAMPLE CreateArrayHandle
////
vtkm::cont::ArrayHandle<vtkm::Float32> outputArray;
////
//// END-EXAMPLE CreateArrayHandle
////
////
//// BEGIN-EXAMPLE ArrayHandleStorageParameter
////
vtkm::cont::ArrayHandle<vtkm::Float32, vtkm::cont::StorageTagBasic> arrayHandle;
////
//// END-EXAMPLE ArrayHandleStorageParameter
////
Foo(outputArray);
Bar(arrayHandle);
}
void ArrayHandleFromInitializerList()
{
////
//// BEGIN-EXAMPLE ArrayHandleFromInitializerList
////
auto fibonacciArray = vtkm::cont::make_ArrayHandle({ 0, 1, 1, 2, 3, 5, 8, 13 });
////
//// END-EXAMPLE ArrayHandleFromInitializerList
////
VTKM_TEST_ASSERT(fibonacciArray.GetNumberOfValues() == 8);
auto portal = fibonacciArray.ReadPortal();
VTKM_TEST_ASSERT(test_equal(portal.Get(0), 0));
VTKM_TEST_ASSERT(test_equal(portal.Get(1), 1));
VTKM_TEST_ASSERT(test_equal(portal.Get(2), 1));
VTKM_TEST_ASSERT(test_equal(portal.Get(3), 2));
VTKM_TEST_ASSERT(test_equal(portal.Get(4), 3));
VTKM_TEST_ASSERT(test_equal(portal.Get(5), 5));
VTKM_TEST_ASSERT(test_equal(portal.Get(6), 8));
VTKM_TEST_ASSERT(test_equal(portal.Get(7), 13));
////
//// BEGIN-EXAMPLE ArrayHandleFromInitializerListTyped
////
vtkm::cont::ArrayHandle<vtkm::FloatDefault> inputArray =
vtkm::cont::make_ArrayHandle<vtkm::FloatDefault>({ 1.4142f, 2.7183f, 3.1416f });
////
//// END-EXAMPLE ArrayHandleFromInitializerListTyped
////
VTKM_TEST_ASSERT(inputArray.GetNumberOfValues() == 3);
auto portal2 = inputArray.ReadPortal();
VTKM_TEST_ASSERT(test_equal(portal2.Get(0), 1.4142));
VTKM_TEST_ASSERT(test_equal(portal2.Get(1), 2.7183));
VTKM_TEST_ASSERT(test_equal(portal2.Get(2), 3.1416));
}
void ArrayHandleFromCArray()
{
////
//// BEGIN-EXAMPLE ArrayHandleFromCArray
////
vtkm::Float32 dataBuffer[50];
// Populate dataBuffer with meaningful data. Perhaps read data from a file.
//// PAUSE-EXAMPLE
for (vtkm::Id index = 0; index < 50; index++)
{
dataBuffer[index] = TestValue(index);
}
//// RESUME-EXAMPLE
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray =
vtkm::cont::make_ArrayHandle(dataBuffer, 50, vtkm::CopyFlag::On);
////
//// END-EXAMPLE ArrayHandleFromCArray
////
CheckArrayValues(inputArray);
}
vtkm::Float32 GetValueForArray(vtkm::Id index)
{
return TestValue(index);
}
void AllocateAndFillArrayHandle()
{
////
//// BEGIN-EXAMPLE ArrayHandlePopulate
////
////
//// BEGIN-EXAMPLE ArrayHandleAllocate
////
vtkm::cont::ArrayHandle<vtkm::Float32> arrayHandle;
const vtkm::Id ARRAY_SIZE = 50;
arrayHandle.Allocate(ARRAY_SIZE);
////
//// END-EXAMPLE ArrayHandleAllocate
////
// Usually it is easier to just use the auto keyword.
using PortalType = vtkm::cont::ArrayHandle<vtkm::Float32>::WritePortalType;
PortalType portal = arrayHandle.WritePortal();
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
{
portal.Set(index, GetValueForArray(index));
}
////
//// END-EXAMPLE ArrayHandlePopulate
////
CheckArrayValues(arrayHandle);
{
vtkm::cont::ArrayHandle<vtkm::Float32> srcArray = arrayHandle;
vtkm::cont::ArrayHandle<vtkm::Float32> destArray;
////
//// BEGIN-EXAMPLE ArrayHandleDeepCopy
////
destArray.DeepCopyFrom(srcArray);
////
//// END-EXAMPLE ArrayHandleDeepCopy
////
VTKM_TEST_ASSERT(srcArray != destArray);
VTKM_TEST_ASSERT(test_equal_ArrayHandles(srcArray, destArray));
}
////
//// BEGIN-EXAMPLE ArrayRangeCompute
////
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray =
vtkm::cont::ArrayRangeCompute(arrayHandle);
auto rangePortal = rangeArray.ReadPortal();
for (vtkm::Id index = 0; index < rangePortal.GetNumberOfValues(); ++index)
{
vtkm::Range componentRange = rangePortal.Get(index);
std::cout << "Values for component " << index << " go from " << componentRange.Min
<< " to " << componentRange.Max << std::endl;
}
////
//// END-EXAMPLE ArrayRangeCompute
////
vtkm::Range range = rangePortal.Get(0);
VTKM_TEST_ASSERT(test_equal(range.Min, TestValue(0)), "Bad min value.");
VTKM_TEST_ASSERT(test_equal(range.Max, TestValue(ARRAY_SIZE - 1)), "Bad max value.");
////
//// BEGIN-EXAMPLE ArrayHandleReallocate
////
// Add space for 10 more values at the end of the array.
arrayHandle.Allocate(arrayHandle.GetNumberOfValues() + 10, vtkm::CopyFlag::On);
////
//// END-EXAMPLE ArrayHandleReallocate
////
}
////
//// BEGIN-EXAMPLE ArrayOutOfScope
////
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Float32> BadDataLoad()
{
std::vector<vtkm::Float32> dataBuffer;
// Populate dataBuffer with meaningful data. Perhaps read data from a file.
//// PAUSE-EXAMPLE
dataBuffer.resize(50);
for (std::size_t index = 0; index < 50; index++)
{
dataBuffer[index] = TestValue(index);
}
//// RESUME-EXAMPLE
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray =
vtkm::cont::make_ArrayHandle(dataBuffer, vtkm::CopyFlag::Off);
//// PAUSE-EXAMPLE
CheckArrayValues(inputArray);
//// RESUME-EXAMPLE
return inputArray;
// THIS IS WRONG! At this point dataBuffer goes out of scope and deletes its
// memory. However, inputArray has a pointer to that memory, which becomes an
// invalid pointer in the returned object. Bad things will happen when the
// ArrayHandle is used.
}
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Float32> SafeDataLoad1()
{
////
//// BEGIN-EXAMPLE ArrayHandleFromVector
////
std::vector<vtkm::Float32> dataBuffer;
// Populate dataBuffer with meaningful data. Perhaps read data from a file.
//// PAUSE-EXAMPLE
dataBuffer.resize(50);
for (std::size_t index = 0; index < 50; index++)
{
dataBuffer[index] = TestValue(index);
}
//// RESUME-EXAMPLE
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray =
//// LABEL CopyFlagOn
vtkm::cont::make_ArrayHandle(dataBuffer, vtkm::CopyFlag::On);
////
//// END-EXAMPLE ArrayHandleFromVector
////
return inputArray;
// This is safe.
}
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Float32> SafeDataLoad2()
{
std::vector<vtkm::Float32> dataBuffer;
// Populate dataBuffer with meaningful data. Perhaps read data from a file.
//// PAUSE-EXAMPLE
dataBuffer.resize(50);
for (std::size_t index = 0; index < 50; index++)
{
dataBuffer[index] = TestValue(index);
}
//// RESUME-EXAMPLE
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray =
//// LABEL MoveVector
vtkm::cont::make_ArrayHandleMove(std::move(dataBuffer));
return inputArray;
// This is safe.
}
////
//// END-EXAMPLE ArrayOutOfScope
////
void ArrayHandleFromVector()
{
BadDataLoad();
}
void CheckSafeDataLoad()
{
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray1 = SafeDataLoad1();
CheckArrayValues(inputArray1);
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray2 = SafeDataLoad2();
CheckArrayValues(inputArray2);
}
////
//// BEGIN-EXAMPLE SimpleArrayPortal
////
template<typename T>
class SimpleScalarArrayPortal
{
public:
using ValueType = T;
// There is no specification for creating array portals, but they generally
// need a constructor like this to be practical.
VTKM_EXEC_CONT
SimpleScalarArrayPortal(ValueType* array, vtkm::Id numberOfValues)
: Array(array)
, NumberOfValues(numberOfValues)
{
}
VTKM_EXEC_CONT
SimpleScalarArrayPortal()
: Array(NULL)
, NumberOfValues(0)
{
}
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; }
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const { return this->Array[index]; }
VTKM_EXEC_CONT
void Set(vtkm::Id index, ValueType value) const { this->Array[index] = value; }
private:
ValueType* Array;
vtkm::Id NumberOfValues;
};
////
//// END-EXAMPLE SimpleArrayPortal
////
////
//// BEGIN-EXAMPLE ArrayPortalToIterators
////
template<typename PortalType>
VTKM_CONT std::vector<typename PortalType::ValueType> CopyArrayPortalToVector(
const PortalType& portal)
{
using ValueType = typename PortalType::ValueType;
std::vector<ValueType> result(static_cast<std::size_t>(portal.GetNumberOfValues()));
vtkm::cont::ArrayPortalToIterators<PortalType> iterators(portal);
std::copy(iterators.GetBegin(), iterators.GetEnd(), result.begin());
return result;
}
////
//// END-EXAMPLE ArrayPortalToIterators
////
void TestArrayPortalVectors()
{
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray = SafeDataLoad1();
std::vector<vtkm::Float32> buffer = CopyArrayPortalToVector(inputArray.ReadPortal());
VTKM_TEST_ASSERT(static_cast<vtkm::Id>(buffer.size()) ==
inputArray.GetNumberOfValues(),
"Vector was sized wrong.");
for (vtkm::Id index = 0; index < inputArray.GetNumberOfValues(); index++)
{
VTKM_TEST_ASSERT(
test_equal(buffer[static_cast<std::size_t>(index)], TestValue(index)),
"Bad data value.");
}
SimpleScalarArrayPortal<vtkm::Float32> portal(&buffer.at(0),
static_cast<vtkm::Id>(buffer.size()));
////
//// BEGIN-EXAMPLE ArrayPortalToIteratorBeginEnd
////
std::vector<vtkm::Float32> myContainer(
static_cast<std::size_t>(portal.GetNumberOfValues()));
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(portal),
vtkm::cont::ArrayPortalToIteratorEnd(portal),
myContainer.begin());
////
//// END-EXAMPLE ArrayPortalToIteratorBeginEnd
////
for (vtkm::Id index = 0; index < inputArray.GetNumberOfValues(); index++)
{
VTKM_TEST_ASSERT(
test_equal(myContainer[static_cast<std::size_t>(index)], TestValue(index)),
"Bad data value.");
}
}
////
//// BEGIN-EXAMPLE ControlPortals
////
template<typename T, typename Storage>
void SortCheckArrayHandle(vtkm::cont::ArrayHandle<T, Storage> arrayHandle)
{
using WritePortalType = typename vtkm::cont::ArrayHandle<T, Storage>::WritePortalType;
using ReadPortalType = typename vtkm::cont::ArrayHandle<T, Storage>::ReadPortalType;
WritePortalType readwritePortal = arrayHandle.WritePortal();
// This is actually pretty dumb. Sorting would be generally faster in
// parallel in the execution environment using the device adapter algorithms.
std::sort(vtkm::cont::ArrayPortalToIteratorBegin(readwritePortal),
vtkm::cont::ArrayPortalToIteratorEnd(readwritePortal));
ReadPortalType readPortal = arrayHandle.ReadPortal();
for (vtkm::Id index = 1; index < readPortal.GetNumberOfValues(); index++)
{
if (readPortal.Get(index - 1) > readPortal.Get(index))
{
//// PAUSE-EXAMPLE
VTKM_TEST_FAIL("Sorting is wrong!");
//// RESUME-EXAMPLE
std::cout << "Sorting is wrong!" << std::endl;
break;
}
}
}
////
//// END-EXAMPLE ControlPortals
////
void TestControlPortalsExample()
{
SortCheckArrayHandle(SafeDataLoad2());
}
////
//// BEGIN-EXAMPLE ExecutionPortals
////
template<typename InputPortalType, typename OutputPortalType>
struct DoubleFunctor : public vtkm::exec::FunctorBase
{
InputPortalType InputPortal;
OutputPortalType OutputPortal;
VTKM_CONT
DoubleFunctor(InputPortalType inputPortal, OutputPortalType outputPortal)
: InputPortal(inputPortal)
, OutputPortal(outputPortal)
{
}
VTKM_EXEC
void operator()(vtkm::Id index) const
{
this->OutputPortal.Set(index, 2 * this->InputPortal.Get(index));
}
};
template<typename T, typename Device>
void DoubleArray(vtkm::cont::ArrayHandle<T> inputArray,
vtkm::cont::ArrayHandle<T> outputArray,
Device)
{
vtkm::Id numValues = inputArray.GetNumberOfValues();
vtkm::cont::Token token;
auto inputPortal = inputArray.PrepareForInput(Device{}, token);
auto outputPortal = outputArray.PrepareForOutput(numValues, Device{}, token);
// Token is now attached to inputPortal and outputPortal. Those two portals
// are guaranteed to be valid until token goes out of scope at the end of
// this function.
DoubleFunctor<decltype(inputPortal), decltype(outputPortal)> functor(inputPortal,
outputPortal);
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(functor, numValues);
}
////
//// END-EXAMPLE ExecutionPortals
////
void TestExecutionPortalsExample()
{
vtkm::cont::ArrayHandle<vtkm::Float32> inputArray = SafeDataLoad1();
CheckArrayValues(inputArray);
vtkm::cont::ArrayHandle<vtkm::Float32> outputArray;
DoubleArray(inputArray, outputArray, vtkm::cont::DeviceAdapterTagSerial());
CheckArrayValues(outputArray, 2);
}
void Test()
{
BasicConstruction();
ArrayHandleFromInitializerList();
ArrayHandleFromCArray();
ArrayHandleFromVector();
AllocateAndFillArrayHandle();
CheckSafeDataLoad();
TestArrayPortalVectors();
TestControlPortalsExample();
TestExecutionPortalsExample();
}
} // anonymous namespace
int GuideExampleArrayHandle(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,321 @@
//============================================================================
// 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/exec/CellEdge.h>
#include <vtkm/exec/CellFace.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/ScatterCounting.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleGroupVec.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/ConvertNumComponentsToOffsets.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
struct ExtractEdges
{
////
//// BEGIN-EXAMPLE CellEdge
////
struct EdgesCount : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn, FieldOutCell numEdgesInCell);
using ExecutionSignature = void(CellShape, PointCount, _2);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC void operator()(CellShapeTag cellShape,
vtkm::IdComponent numPointsInCell,
vtkm::IdComponent& numEdges) const
{
vtkm::ErrorCode status =
vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, numEdges);
if (status != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(status));
}
}
};
////
//// BEGIN-EXAMPLE ComplexWorklet
////
struct EdgesExtract : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn, FieldOutCell edgeIndices);
using ExecutionSignature = void(CellShape, PointIndices, VisitIndex, _2);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag,
typename PointIndexVecType,
typename EdgeIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::IdComponent edgeIndex,
EdgeIndexVecType& edgeIndices) const
{
////
//// END-EXAMPLE ComplexWorklet
////
vtkm::IdComponent numPointsInCell =
globalPointIndicesForCell.GetNumberOfComponents();
vtkm::ErrorCode error;
vtkm::IdComponent pointInCellIndex0;
error = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 0, edgeIndex, cellShape, pointInCellIndex0);
if (error != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(error));
return;
}
vtkm::IdComponent pointInCellIndex1;
error = vtkm::exec::CellEdgeLocalIndex(
numPointsInCell, 1, edgeIndex, cellShape, pointInCellIndex1);
if (error != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(error));
return;
}
edgeIndices[0] = globalPointIndicesForCell[pointInCellIndex0];
edgeIndices[1] = globalPointIndicesForCell[pointInCellIndex1];
}
};
////
//// END-EXAMPLE CellEdge
////
template<typename CellSetInType>
VTKM_CONT vtkm::cont::CellSetSingleType<> Run(const CellSetInType& cellSetIn)
{
// Count how many edges each cell has
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
vtkm::worklet::DispatcherMapTopology<EdgesCount> countDispatcher;
countDispatcher.Invoke(cellSetIn, edgeCounts);
// Set up a "scatter" to create an output entry for each edge in the input
vtkm::worklet::ScatterCounting scatter(edgeCounts);
// Get the cell index array for all the edges
vtkm::cont::ArrayHandle<vtkm::Id> edgeIndices;
vtkm::worklet::DispatcherMapTopology<EdgesExtract> extractDispatcher(scatter);
extractDispatcher.Invoke(cellSetIn,
vtkm::cont::make_ArrayHandleGroupVec<2>(edgeIndices));
// Construct the resulting cell set and return
vtkm::cont::CellSetSingleType<> cellSetOut;
cellSetOut.Fill(
cellSetIn.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, edgeIndices);
return cellSetOut;
}
};
void TryExtractEdges()
{
std::cout << "Trying extract edges worklets." << std::endl;
vtkm::cont::DataSet dataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DExplicitDataSet5();
ExtractEdges extractEdges;
vtkm::cont::CellSetSingleType<> edgeCells = extractEdges.Run(dataSet.GetCellSet());
VTKM_TEST_ASSERT(edgeCells.GetNumberOfPoints() == 11,
"Output has wrong number of points");
VTKM_TEST_ASSERT(edgeCells.GetNumberOfCells() == 35,
"Output has wrong number of cells");
}
struct ExtractFaces
{
////
//// BEGIN-EXAMPLE CellFace
////
struct FacesCount : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn, FieldOutCell numFacesInCell);
using ExecutionSignature = void(CellShape, _2);
using InputDomain = _1;
template<typename CellShapeTag>
VTKM_EXEC void operator()(CellShapeTag cellShape, vtkm::IdComponent& numFaces) const
{
vtkm::ErrorCode status = vtkm::exec::CellFaceNumberOfFaces(cellShape, numFaces);
if (status != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(status));
}
}
};
struct FacesCountPoints : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn,
FieldOutCell numPointsInFace,
FieldOutCell faceShape);
using ExecutionSignature = void(CellShape, VisitIndex, _2, _3);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag>
VTKM_EXEC void operator()(CellShapeTag cellShape,
vtkm::IdComponent faceIndex,
vtkm::IdComponent& numPointsInFace,
vtkm::UInt8& faceShape) const
{
vtkm::exec::CellFaceNumberOfPoints(faceIndex, cellShape, numPointsInFace);
switch (numPointsInFace)
{
case 3:
faceShape = vtkm::CELL_SHAPE_TRIANGLE;
break;
case 4:
faceShape = vtkm::CELL_SHAPE_QUAD;
break;
default:
faceShape = vtkm::CELL_SHAPE_POLYGON;
break;
}
}
};
struct FacesExtract : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn, FieldOutCell faceIndices);
using ExecutionSignature = void(CellShape, PointIndices, VisitIndex, _2);
using InputDomain = _1;
using ScatterType = vtkm::worklet::ScatterCounting;
template<typename CellShapeTag,
typename PointIndexVecType,
typename FaceIndexVecType>
VTKM_EXEC void operator()(CellShapeTag cellShape,
const PointIndexVecType& globalPointIndicesForCell,
vtkm::IdComponent faceIndex,
FaceIndexVecType& faceIndices) const
{
vtkm::IdComponent numPointsInFace = faceIndices.GetNumberOfComponents();
for (vtkm::IdComponent pointInFaceIndex = 0; pointInFaceIndex < numPointsInFace;
pointInFaceIndex++)
{
vtkm::IdComponent pointInCellIndex;
vtkm::ErrorCode error = vtkm::exec::CellFaceLocalIndex(
pointInFaceIndex, faceIndex, cellShape, pointInCellIndex);
if (error != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(error));
return;
}
faceIndices[pointInFaceIndex] = globalPointIndicesForCell[pointInCellIndex];
}
}
};
////
//// END-EXAMPLE CellFace
////
template<typename CellSetInType>
VTKM_CONT vtkm::cont::CellSetExplicit<> Run(const CellSetInType& cellSetIn)
{
// Count how many faces each cell has
vtkm::cont::ArrayHandle<vtkm::IdComponent> faceCounts;
vtkm::worklet::DispatcherMapTopology<FacesCount> countDispatcher;
countDispatcher.Invoke(cellSetIn, faceCounts);
// Set up a "scatter" to create an output entry for each face in the input
vtkm::worklet::ScatterCounting scatter(faceCounts);
// Count how many points each face has. Also get the shape of each face.
vtkm::cont::ArrayHandle<vtkm::IdComponent> pointsPerFace;
vtkm::cont::ArrayHandle<vtkm::UInt8> faceShapes;
vtkm::worklet::DispatcherMapTopology<FacesCountPoints> countPointsDispatcher(
scatter);
countPointsDispatcher.Invoke(cellSetIn, pointsPerFace, faceShapes);
// To construct an ArrayHandleGroupVecVariable, we need to convert
// pointsPerFace to an array of offsets
vtkm::Id faceIndicesSize;
vtkm::cont::ArrayHandle<vtkm::Id> faceIndexOffsets =
vtkm::cont::ConvertNumComponentsToOffsets(pointsPerFace, faceIndicesSize);
// We need to preallocate the array for faceIndices (because that is the
// way ArrayHandleGroupVecVariable works). We use the value previously
// returned from ConvertNumComponentsToOffsets.
vtkm::cont::ArrayHandle<vtkm::Id> faceIndices;
faceIndices.Allocate(faceIndicesSize);
// Get the cell index array for all the faces
vtkm::worklet::DispatcherMapTopology<FacesExtract> extractDispatcher(scatter);
extractDispatcher.Invoke(
cellSetIn,
vtkm::cont::make_ArrayHandleGroupVecVariable(faceIndices, faceIndexOffsets));
// Construct the resulting cell set and return
vtkm::cont::CellSetExplicit<> cellSetOut;
cellSetOut.Fill(
cellSetIn.GetNumberOfPoints(), faceShapes, faceIndices, faceIndexOffsets);
return cellSetOut;
}
};
void TryExtractFaces()
{
std::cout << "Trying extract faces worklets." << std::endl;
vtkm::cont::DataSet dataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DExplicitDataSet5();
ExtractFaces extractFaces;
vtkm::cont::CellSetExplicit<> faceCells = extractFaces.Run(dataSet.GetCellSet());
VTKM_TEST_ASSERT(faceCells.GetNumberOfPoints() == 11,
"Output has wrong number of points");
VTKM_TEST_ASSERT(faceCells.GetNumberOfCells() == 20,
"Output has wrong number of cells");
VTKM_TEST_ASSERT(faceCells.GetCellShape(0) == vtkm::CELL_SHAPE_QUAD, "Face wrong");
vtkm::Id4 quadIndices;
faceCells.GetIndices(0, quadIndices);
VTKM_TEST_ASSERT(test_equal(quadIndices, vtkm::Id4(0, 3, 7, 4)), "Face wrong");
VTKM_TEST_ASSERT(faceCells.GetCellShape(12) == vtkm::CELL_SHAPE_TRIANGLE,
"Face wrong");
vtkm::Id3 triIndices;
faceCells.GetIndices(12, triIndices);
VTKM_TEST_ASSERT(test_equal(triIndices, vtkm::Id3(8, 10, 6)), "Face wrong");
}
void Run()
{
TryExtractEdges();
TryExtractFaces();
}
} // anonymous namespace
int GuideExampleCellEdgesFaces(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
}

@ -0,0 +1,175 @@
//=============================================================================
//
// 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/worklet/WorkletMapField.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/CellLocatorBoundingIntervalHierarchy.h>
#include <vtkm/cont/CellLocatorGeneral.h>
#include <vtkm/cont/DataSetBuilderRectilinear.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/VecFromPortalPermute.h>
#include <vtkm/exec/CellInterpolate.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
constexpr vtkm::Id DimensionSize = 50;
const vtkm::Id3 DimensionSizes = vtkm::Id3(DimensionSize);
////
//// BEGIN-EXAMPLE UseCellLocator
////
struct QueryCellsWorklet : public vtkm::worklet::WorkletMapField
{
using ControlSignature =
void(FieldIn, ExecObject, WholeCellSetIn<Cell, Point>, WholeArrayIn, FieldOut);
using ExecutionSignature = void(_1, _2, _3, _4, _5);
template<typename Point,
typename CellLocatorExecObject,
typename CellSet,
typename FieldPortal,
typename OutType>
VTKM_EXEC void operator()(const Point& point,
const CellLocatorExecObject& cellLocator,
const CellSet& cellSet,
const FieldPortal& field,
OutType& out) const
{
// Use the cell locator to find the cell containing the point and the parametric
// coordinates within that cell.
vtkm::Id cellId;
vtkm::Vec3f parametric;
////
//// BEGIN-EXAMPLE HandleErrorCode
////
vtkm::ErrorCode status = cellLocator.FindCell(point, cellId, parametric);
if (status != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(status));
}
////
//// END-EXAMPLE HandleErrorCode
////
// Use this information to interpolate the point field to the given location.
if (cellId >= 0)
{
// Get shape information about the cell containing the point coordinate
auto cellShape = cellSet.GetCellShape(cellId);
auto indices = cellSet.GetIndices(cellId);
// Make a Vec-like containing the field data at the cell's points
auto fieldValues = vtkm::make_VecFromPortalPermute(&indices, &field);
// Do the interpolation
vtkm::exec::CellInterpolate(fieldValues, parametric, cellShape, out);
}
else
{
this->RaiseError("Given point outside of the cell set.");
}
}
};
//
// Later in the associated Filter class...
//
//// PAUSE-EXAMPLE
struct DemoQueryCells
{
vtkm::cont::Invoker Invoke;
vtkm::cont::ArrayHandle<vtkm::Vec3f> QueryPoints;
template<typename FieldType, typename Storage>
VTKM_CONT vtkm::cont::ArrayHandle<FieldType> Run(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<FieldType, Storage>& inputField)
{
//// RESUME-EXAMPLE
////
//// BEGIN-EXAMPLE ConstructCellLocator
////
vtkm::cont::CellLocatorGeneral cellLocator;
cellLocator.SetCellSet(inDataSet.GetCellSet());
cellLocator.SetCoordinates(inDataSet.GetCoordinateSystem());
cellLocator.Update();
////
//// END-EXAMPLE ConstructCellLocator
////
vtkm::cont::ArrayHandle<FieldType> interpolatedField;
this->Invoke(QueryCellsWorklet{},
this->QueryPoints,
&cellLocator,
inDataSet.GetCellSet(),
inputField,
interpolatedField);
////
//// END-EXAMPLE UseCellLocator
////
return interpolatedField;
}
};
void TestCellLocator()
{
using ValueType = vtkm::Vec3f;
using ArrayType = vtkm::cont::ArrayHandle<ValueType>;
vtkm::cont::DataSet data = vtkm::cont::DataSetBuilderUniform::Create(DimensionSizes);
ArrayType inField;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleUniformPointCoordinates(
DimensionSizes, ValueType(0.0f), ValueType(2.0f)),
inField);
DemoQueryCells demo;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleUniformPointCoordinates(
DimensionSizes - vtkm::Id3(1), ValueType(0.5f)),
demo.QueryPoints);
ArrayType interpolated = demo.Run(data, inField);
vtkm::cont::ArrayHandleUniformPointCoordinates expected(
DimensionSizes - vtkm::Id3(1), ValueType(1.0f), ValueType(2.0f));
std::cout << "Expected: ";
vtkm::cont::printSummary_ArrayHandle(expected, std::cout);
std::cout << "Interpolated: ";
vtkm::cont::printSummary_ArrayHandle(interpolated, std::cout);
VTKM_TEST_ASSERT(test_equal_portals(expected.ReadPortal(), interpolated.ReadPortal()));
}
void Run()
{
TestCellLocator();
}
} // anonymous namespace
int GuideExampleCellLocator(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
}

@ -0,0 +1,153 @@
//============================================================================
// 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/exec/CellDerivative.h>
#include <vtkm/exec/CellInterpolate.h>
#include <vtkm/exec/ParametricCoordinates.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
////
//// BEGIN-EXAMPLE CellCenters
////
struct CellCenters : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn,
FieldInPoint inputField,
FieldOutCell outputField);
using ExecutionSignature = void(CellShape, PointCount, _2, _3);
using InputDomain = _1;
template<typename CellShapeTag, typename FieldInVecType, typename FieldOutType>
VTKM_EXEC void operator()(CellShapeTag shape,
vtkm::IdComponent pointCount,
const FieldInVecType& inputField,
FieldOutType& outputField) const
{
vtkm::Vec3f center;
vtkm::ErrorCode status =
vtkm::exec::ParametricCoordinatesCenter(pointCount, shape, center);
if (status != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(status));
return;
}
vtkm::exec::CellInterpolate(inputField, center, shape, outputField);
}
};
////
//// END-EXAMPLE CellCenters
////
void TryCellCenters()
{
std::cout << "Trying CellCenters worklet." << std::endl;
vtkm::cont::DataSet dataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DUniformDataSet0();
using ArrayType = vtkm::cont::ArrayHandle<vtkm::Float32>;
ArrayType centers;
vtkm::worklet::DispatcherMapTopology<CellCenters> dispatcher;
dispatcher.Invoke(dataSet.GetCellSet(),
dataSet.GetField("pointvar").GetData().AsArrayHandle<ArrayType>(),
centers);
vtkm::cont::printSummary_ArrayHandle(centers, std::cout);
std::cout << std::endl;
VTKM_TEST_ASSERT(centers.GetNumberOfValues() ==
dataSet.GetCellSet().GetNumberOfCells(),
"Bad number of cells.");
VTKM_TEST_ASSERT(test_equal(60.1875, centers.ReadPortal().Get(0)), "Bad first value.");
}
////
//// BEGIN-EXAMPLE CellDerivatives
////
struct CellDerivatives : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn,
FieldInPoint inputField,
FieldInPoint pointCoordinates,
FieldOutCell outputField);
using ExecutionSignature = void(CellShape, PointCount, _2, _3, _4);
using InputDomain = _1;
template<typename CellShapeTag,
typename FieldInVecType,
typename PointCoordVecType,
typename FieldOutType>
VTKM_EXEC void operator()(CellShapeTag shape,
vtkm::IdComponent pointCount,
const FieldInVecType& inputField,
const PointCoordVecType& pointCoordinates,
FieldOutType& outputField) const
{
vtkm::Vec3f center;
vtkm::ErrorCode status =
vtkm::exec::ParametricCoordinatesCenter(pointCount, shape, center);
if (status != vtkm::ErrorCode::Success)
{
this->RaiseError(vtkm::ErrorString(status));
return;
}
vtkm::exec::CellDerivative(inputField, pointCoordinates, center, shape, outputField);
}
};
////
//// END-EXAMPLE CellDerivatives
////
void TryCellDerivatives()
{
std::cout << "Trying CellDerivatives worklet." << std::endl;
vtkm::cont::DataSet dataSet =
vtkm::cont::testing::MakeTestDataSet().Make3DUniformDataSet0();
using ArrayType = vtkm::cont::ArrayHandle<vtkm::Float32>;
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> derivatives;
vtkm::worklet::DispatcherMapTopology<CellDerivatives> dispatcher;
dispatcher.Invoke(dataSet.GetCellSet(),
dataSet.GetField("pointvar").GetData().AsArrayHandle<ArrayType>(),
dataSet.GetCoordinateSystem().GetData(),
derivatives);
vtkm::cont::printSummary_ArrayHandle(derivatives, std::cout);
std::cout << std::endl;
VTKM_TEST_ASSERT(derivatives.GetNumberOfValues() ==
dataSet.GetCellSet().GetNumberOfCells(),
"Bad number of cells.");
VTKM_TEST_ASSERT(
test_equal(vtkm::make_Vec(10.025, 30.075, 60.125), derivatives.ReadPortal().Get(0)),
"Bad first value.");
}
void Run()
{
TryCellCenters();
TryCellDerivatives();
}
} // anonymous namespace
int GuideExampleCellOperations(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
}

@ -0,0 +1,150 @@
//============================================================================
// 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/CellShape.h>
#include <vtkm/CellTraits.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/testing/Testing.h>
namespace CellShapesExamples
{
////
//// BEGIN-EXAMPLE CellShapeIdToTag
////
void CellFunction(vtkm::CellShapeTagTriangle)
{
std::cout << "In CellFunction for triangles." << std::endl;
}
void DoSomethingWithACell()
{
// Calls CellFunction overloaded with a vtkm::CellShapeTagTriangle.
CellFunction(vtkm::CellShapeIdToTag<vtkm::CELL_SHAPE_TRIANGLE>::Tag());
}
////
//// END-EXAMPLE CellShapeIdToTag
////
////
//// BEGIN-EXAMPLE GenericCellNormal
////
namespace detail
{
template<typename PointCoordinatesVector, typename WorkletType>
VTKM_EXEC_CONT typename PointCoordinatesVector::ComponentType CellNormalImpl(
const PointCoordinatesVector& pointCoordinates,
vtkm::CellTopologicalDimensionsTag<2>,
const WorkletType& worklet)
{
if (pointCoordinates.GetNumberOfComponents() >= 3)
{
return vtkm::TriangleNormal(
pointCoordinates[0], pointCoordinates[1], pointCoordinates[2]);
}
else
{
worklet.RaiseError("Degenerate polygon.");
return typename PointCoordinatesVector::ComponentType();
}
}
template<typename PointCoordinatesVector,
vtkm::IdComponent Dimensions,
typename WorkletType>
VTKM_EXEC_CONT typename PointCoordinatesVector::ComponentType CellNormalImpl(
const PointCoordinatesVector&,
vtkm::CellTopologicalDimensionsTag<Dimensions>,
const WorkletType& worklet)
{
worklet.RaiseError("Only polygons supported for cell normals.");
return typename PointCoordinatesVector::ComponentType();
}
} // namespace detail
template<typename CellShape, typename PointCoordinatesVector, typename WorkletType>
VTKM_EXEC_CONT typename PointCoordinatesVector::ComponentType CellNormal(
CellShape,
const PointCoordinatesVector& pointCoordinates,
const WorkletType& worklet)
{
return detail::CellNormalImpl(
pointCoordinates,
typename vtkm::CellTraits<CellShape>::TopologicalDimensionsTag(),
worklet);
}
template<typename PointCoordinatesVector, typename WorkletType>
VTKM_EXEC_CONT typename PointCoordinatesVector::ComponentType CellNormal(
vtkm::CellShapeTagGeneric shape,
const PointCoordinatesVector& pointCoordinates,
const WorkletType& worklet)
{
switch (shape.Id)
{
vtkmGenericCellShapeMacro(
return CellNormal(CellShapeTag(), pointCoordinates, worklet));
default:
worklet.RaiseError("Unknown cell type.");
return typename PointCoordinatesVector::ComponentType();
}
}
////
//// END-EXAMPLE GenericCellNormal
////
struct FakeWorklet : vtkm::exec::FunctorBase
{
};
void Run()
{
std::cout << "Basic identifier to tag." << std::endl;
DoSomethingWithACell();
std::cout << "Function with dynamic lookup of cell shape." << std::endl;
vtkm::Vec<vtkm::Vec3f, 3> pointCoordinates;
pointCoordinates[0] = vtkm::Vec3f(0.0f, 0.0f, 0.0f);
pointCoordinates[1] = vtkm::Vec3f(1.0f, 0.0f, 0.0f);
pointCoordinates[2] = vtkm::Vec3f(0.0f, 1.0f, 0.0f);
vtkm::Vec3f expectedNormal(0.0f, 0.0f, 1.0f);
char errorBuffer[256];
errorBuffer[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorBuffer, 256);
FakeWorklet worklet;
worklet.SetErrorMessageBuffer(errorMessage);
vtkm::Vec3f normal =
CellNormal(vtkm::CellShapeTagTriangle(), pointCoordinates, worklet);
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), "Error finding normal.");
VTKM_TEST_ASSERT(test_equal(normal, expectedNormal), "Bad normal.");
normal = CellNormal(
vtkm::CellShapeTagGeneric(vtkm::CELL_SHAPE_TRIANGLE), pointCoordinates, worklet);
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), "Error finding normal.");
VTKM_TEST_ASSERT(test_equal(normal, expectedNormal), "Bad normal.");
CellNormal(vtkm::CellShapeTagLine(), pointCoordinates, worklet);
VTKM_TEST_ASSERT(errorMessage.IsErrorRaised(), "Expected error not raised.");
}
} // namespace CellShapesExamples
int GuideExampleCellShapes(int argc, char* argv[])
{
return vtkm::testing::Testing::Run(CellShapesExamples::Run, argc, argv);
}

@ -0,0 +1,111 @@
//============================================================================
// 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/ColorTable.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/cont/testing/Testing.h>
#include <sys/stat.h>
#include <fstream>
namespace
{
static const vtkm::Id TABLE_IMAGE_WIDTH = 150;
static const vtkm::Id TABLE_IMAGE_HEIGHT = 20;
std::string FilenameFriendly(const std::string& name)
{
std::string filename;
for (auto&& ch : name)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')))
{
filename.push_back(ch);
}
else
{
filename.push_back('-');
}
}
return filename;
}
void CreateColorTableImage(const std::string& name)
{
std::cout << "Creating color table " << name << std::endl;
vtkm::cont::ColorTable colorTable(name);
// Create a CanvasRayTracer simply for the color buffer and the ability to
// write out images.
vtkm::rendering::CanvasRayTracer canvas(TABLE_IMAGE_WIDTH, TABLE_IMAGE_HEIGHT);
using ColorBufferType = vtkm::rendering::CanvasRayTracer::ColorBufferType;
ColorBufferType colorBuffer = canvas.GetColorBuffer();
ColorBufferType::WritePortalType colorPortal = colorBuffer.WritePortal();
VTKM_TEST_ASSERT(colorPortal.GetNumberOfValues() ==
TABLE_IMAGE_WIDTH * TABLE_IMAGE_HEIGHT,
"Wrong size of color buffer.");
vtkm::cont::ArrayHandle<vtkm::Vec4ui_8> temp;
colorTable.Sample(TABLE_IMAGE_WIDTH, temp);
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
for (vtkm::Id j = 0; j < TABLE_IMAGE_HEIGHT; ++j)
{
auto tempPortal = temp.ReadPortal();
for (vtkm::Id i = 0; i < TABLE_IMAGE_WIDTH; ++i)
{
auto color = tempPortal.Get(i);
vtkm::Vec4f_32 t(color[0] * conversionToFloatSpace,
color[1] * conversionToFloatSpace,
color[2] * conversionToFloatSpace,
color[3] * conversionToFloatSpace);
colorPortal.Set(j * TABLE_IMAGE_WIDTH + i, t);
}
}
canvas.SaveAs("color-tables/" + FilenameFriendly(name) + ".png");
}
void DoColorTables()
{
#ifndef VTKM_MSVC
// Disabled for MSVC because POSIX mkdir is not supported.
// We can use std::filestyem::create_directories later when we support C++17.
mkdir("color-tables", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
std::ofstream rstTable("color-tables/color-table-presets.rst",
std::ios::out | std::ios::trunc);
rstTable << ".. DO NOT EDIT!\n";
rstTable << ".. Created by GuideExampleColorTables test.\n";
rstTable << "\n";
vtkm::cont::ColorTable table;
std::set<std::string> names = table.GetPresets();
for (auto& n : names)
{
CreateColorTableImage(n);
rstTable << ".. |" << FilenameFriendly(n) << "| image:: images/color-tables/"
<< FilenameFriendly(n) << ".png\n";
}
#endif
}
} // anonymous namespace
int GuideExampleColorTables(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(DoColorTables, argc, argv);
}

@ -0,0 +1,329 @@
//============================================================================
// 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/Range.h>
#include <vtkm/Types.h>
#include <vtkm/VecVariable.h>
#include <vtkm/testing/Testing.h>
namespace
{
void SimpleVectorTypes()
{
////
//// BEGIN-EXAMPLE SimpleVectorTypes
////
vtkm::Vec2f A(1); // A is (1, 1)
A[1] = 3; // A is (1, 3) now
vtkm::Vec2f B = { 4, 5 }; // B is (4, 5)
vtkm::Vec2f C = A + B; // C is (5, 8)
vtkm::FloatDefault manhattanDistance = C[0] + C[1];
////
//// END-EXAMPLE SimpleVectorTypes
////
VTKM_TEST_ASSERT(test_equal(A, vtkm::make_Vec(1, 3)));
VTKM_TEST_ASSERT(test_equal(B, vtkm::make_Vec(4, 5)));
VTKM_TEST_ASSERT(test_equal(C, vtkm::make_Vec(5, 8)));
VTKM_TEST_ASSERT(test_equal(manhattanDistance, 13));
}
void CreatingVectorTypes()
{
////
//// BEGIN-EXAMPLE CreatingVectorTypes
////
vtkm::Vec3f_32 A{ 1 }; // A is (1, 1, 1)
A[1] = 2; // A is now (1, 2, 1)
vtkm::Vec3f_32 B{ 1, 2, 3 }; // B is (1, 2, 3)
vtkm::Vec3f_32 C = vtkm::make_Vec(3, 4, 5); // C is (3, 4, 5)
// Longer Vecs specified with template.
vtkm::Vec<vtkm::Float32, 5> D{ 1 }; // D is (1, 1, 1, 1, 1)
vtkm::Vec<vtkm::Float32, 5> E{ 1, 2, 3, 4, 5 }; // E is (1, 2, 3, 4, 5)
vtkm::Vec<vtkm::Float32, 5> F = { 6, 7, 8, 9, 10 }; // F is (6, 7, 8, 9, 10)
auto G = vtkm::make_Vec(1, 3, 5, 7, 9); // G is (1, 3, 5, 7, 9)
////
//// END-EXAMPLE CreatingVectorTypes
////
VTKM_TEST_ASSERT((A[0] == 1) && (A[1] == 2) && (A[2] == 1),
"A is different than expected.");
VTKM_TEST_ASSERT((B[0] == 1) && (B[1] == 2) && (B[2] == 3),
"B is different than expected.");
VTKM_TEST_ASSERT((C[0] == 3) && (C[1] == 4) && (C[2] == 5),
"C is different than expected.");
VTKM_TEST_ASSERT((D[0] == 1) && (D[1] == 1) && (D[2] == 1) && (D[3] == 1) &&
(D[4] == 1),
"D is different than expected.");
VTKM_TEST_ASSERT((E[0] == 1) && (E[1] == 2) && (E[2] == 3) && (E[3] == 4) &&
(E[4] == 5),
"E is different than expected.");
VTKM_TEST_ASSERT((F[0] == 6) && (F[1] == 7) && (F[2] == 8) && (F[3] == 9) &&
(F[4] == 10),
"F is different than expected.");
VTKM_TEST_ASSERT((G[0] == 1) && (G[1] == 3) && (G[2] == 5) && (G[3] == 7) &&
(G[4] == 9),
"F is different than expected.");
}
void VectorOperations()
{
////
//// BEGIN-EXAMPLE VectorOperations
////
vtkm::Vec3f_32 A{ 1, 2, 3 };
vtkm::Vec3f_32 B{ 4, 5, 6.5 };
vtkm::Vec3f_32 C = A + B; // C is (5, 7, 9.5)
vtkm::Vec3f_32 D = 2.0f * C; // D is (10, 14, 19)
vtkm::Float32 s = vtkm::Dot(A, B); // s is 33.5
bool b1 = (A == B); // b1 is false
bool b2 = (A == vtkm::make_Vec(1, 2, 3)); // b2 is true
vtkm::Vec<vtkm::Float32, 5> E{ 1, 2.5, 3, 4, 5 }; // E is (1, 2, 3, 4, 5)
vtkm::Vec<vtkm::Float32, 5> F{ 6, 7, 8.5, 9, 10.5 }; // F is (6, 7, 8, 9, 10)
vtkm::Vec<vtkm::Float32, 5> G = E + F; // G is (7, 9.5, 11.5, 13, 15.5)
bool b3 = (E == F); // b3 is false
bool b4 = (G == vtkm::make_Vec(7.f, 9.5f, 11.5f, 13.f, 15.5f)); // b4 is true
////
//// END-EXAMPLE VectorOperations
////
VTKM_TEST_ASSERT(test_equal(C, vtkm::Vec3f_32(5, 7, 9.5)), "C is wrong");
VTKM_TEST_ASSERT(test_equal(D, vtkm::Vec3f_32(10, 14, 19)), "D is wrong");
VTKM_TEST_ASSERT(test_equal(s, 33.5), "s is wrong");
VTKM_TEST_ASSERT(!b1, "b1 is wrong");
VTKM_TEST_ASSERT(b2, "b2 is wrong");
VTKM_TEST_ASSERT(!b3, "b3 is wrong");
VTKM_TEST_ASSERT(b4, "b4 is wrong");
}
void EquilateralTriangle()
{
////
//// BEGIN-EXAMPLE EquilateralTriangle
////
vtkm::Vec<vtkm::Vec2f_32, 3> equilateralTriangle = { { 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 0.5f, 0.8660254f } };
////
//// END-EXAMPLE EquilateralTriangle
////
vtkm::Float32 edgeLengthSqr = 1.0;
vtkm::Vec<vtkm::Vec2f_32, 3> edges(equilateralTriangle[1] - equilateralTriangle[0],
equilateralTriangle[2] - equilateralTriangle[0],
equilateralTriangle[2] - equilateralTriangle[1]);
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[0], edges[0]), edgeLengthSqr),
"Bad edge length.");
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[1], edges[1]), edgeLengthSqr),
"Bad edge length.");
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(edges[2], edges[2]), edgeLengthSqr),
"Bad edge length.");
}
////
//// BEGIN-EXAMPLE VecCExample
////
VTKM_EXEC vtkm::VecCConst<vtkm::IdComponent> HexagonIndexToIJK(vtkm::IdComponent index)
{
static const vtkm::IdComponent HexagonIndexToIJKTable[8][3] = {
{ 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
{ 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }
};
return vtkm::make_VecC(HexagonIndexToIJKTable[index], 3);
}
VTKM_EXEC vtkm::IdComponent HexagonIJKToIndex(vtkm::VecCConst<vtkm::IdComponent> ijk)
{
static const vtkm::IdComponent HexagonIJKToIndexTable[2][2][2] = { {
// i=0
{ 0, 4 }, // j=0
{ 3, 7 }, // j=1
},
{
// i=1
{ 1, 5 }, // j=0
{ 2, 6 }, // j=1
} };
return HexagonIJKToIndexTable[ijk[0]][ijk[1]][ijk[2]];
}
////
//// END-EXAMPLE VecCExample
////
////
//// BEGIN-EXAMPLE VecVariableExample
////
vtkm::VecVariable<vtkm::IdComponent, 4> HexagonShortestPath(vtkm::IdComponent startPoint,
vtkm::IdComponent endPoint)
{
vtkm::VecCConst<vtkm::IdComponent> startIJK = HexagonIndexToIJK(startPoint);
vtkm::VecCConst<vtkm::IdComponent> endIJK = HexagonIndexToIJK(endPoint);
vtkm::IdComponent3 currentIJK;
startIJK.CopyInto(currentIJK);
vtkm::VecVariable<vtkm::IdComponent, 4> path;
path.Append(startPoint);
for (vtkm::IdComponent dimension = 0; dimension < 3; dimension++)
{
if (currentIJK[dimension] != endIJK[dimension])
{
currentIJK[dimension] = endIJK[dimension];
path.Append(HexagonIJKToIndex(currentIJK));
}
}
return path;
}
////
//// END-EXAMPLE VecVariableExample
////
void UsingVecCAndVecVariable()
{
vtkm::VecVariable<vtkm::IdComponent, 4> path;
path = HexagonShortestPath(2, 2);
VTKM_TEST_ASSERT(test_equal(path, vtkm::Vec<vtkm::IdComponent, 1>(2)), "Bad path");
path = HexagonShortestPath(0, 7);
VTKM_TEST_ASSERT(test_equal(path, vtkm::IdComponent3(0, 3, 7)), "Bad path");
path = HexagonShortestPath(5, 3);
VTKM_TEST_ASSERT(test_equal(path, vtkm::IdComponent4(5, 4, 7, 3)), "Bad path");
}
void UsingRange()
{
////
//// BEGIN-EXAMPLE UsingRange
////
vtkm::Range range; // default constructor is empty range
bool b1 = range.IsNonEmpty(); // b1 is false
range.Include(0.5); // range now is [0.5 .. 0.5]
bool b2 = range.IsNonEmpty(); // b2 is true
bool b3 = range.Contains(0.5); // b3 is true
bool b4 = range.Contains(0.6); // b4 is false
range.Include(2.0); // range is now [0.5 .. 2]
bool b5 = range.Contains(0.5); // b3 is true
bool b6 = range.Contains(0.6); // b4 is true
range.Include(vtkm::Range(-1, 1)); // range is now [-1 .. 2]
//// PAUSE-EXAMPLE
VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 2)), "Bad range");
//// RESUME-EXAMPLE
range.Include(vtkm::Range(3, 4)); // range is now [-1 .. 4]
//// PAUSE-EXAMPLE
VTKM_TEST_ASSERT(test_equal(range, vtkm::Range(-1, 4)), "Bad range");
//// RESUME-EXAMPLE
vtkm::Float64 lower = range.Min; // lower is -1
vtkm::Float64 upper = range.Max; // upper is 4
vtkm::Float64 length = range.Length(); // length is 5
vtkm::Float64 center = range.Center(); // center is 1.5
////
//// END-EXAMPLE UsingRange
////
VTKM_TEST_ASSERT(!b1, "Bad non empty.");
VTKM_TEST_ASSERT(b2, "Bad non empty.");
VTKM_TEST_ASSERT(b3, "Bad contains.");
VTKM_TEST_ASSERT(!b4, "Bad contains.");
VTKM_TEST_ASSERT(b5, "Bad contains.");
VTKM_TEST_ASSERT(b6, "Bad contains.");
VTKM_TEST_ASSERT(test_equal(lower, -1), "Bad lower");
VTKM_TEST_ASSERT(test_equal(upper, 4), "Bad upper");
VTKM_TEST_ASSERT(test_equal(length, 5), "Bad length");
VTKM_TEST_ASSERT(test_equal(center, 1.5), "Bad center");
}
void UsingBounds()
{
////
//// BEGIN-EXAMPLE UsingBounds
////
vtkm::Bounds bounds; // default constructor makes empty
bool b1 = bounds.IsNonEmpty(); // b1 is false
bounds.Include(vtkm::make_Vec(0.5, 2.0, 0.0)); // bounds contains only
// the point [0.5, 2, 0]
bool b2 = bounds.IsNonEmpty(); // b2 is true
bool b3 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b3 is true
bool b4 = bounds.Contains(vtkm::make_Vec(1, 1, 1)); // b4 is false
bool b5 = bounds.Contains(vtkm::make_Vec(0, 0, 0)); // b5 is false
bounds.Include(vtkm::make_Vec(4, -1, 2)); // bounds is region [0.5 .. 4] in X,
// [-1 .. 2] in Y,
// and [0 .. 2] in Z
//// PAUSE-EXAMPLE
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0.5, 4, -1, 2, 0, 2)), "");
//// RESUME-EXAMPLE
bool b6 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b6 is true
bool b7 = bounds.Contains(vtkm::make_Vec(1, 1, 1)); // b7 is true
bool b8 = bounds.Contains(vtkm::make_Vec(0, 0, 0)); // b8 is false
vtkm::Bounds otherBounds(vtkm::make_Vec(0, 0, 0), vtkm::make_Vec(3, 3, 3));
// otherBounds is region [0 .. 3] in X, Y, and Z
bounds.Include(otherBounds); // bounds is now region [0 .. 4] in X,
// [-1 .. 3] in Y,
// and [0 .. 3] in Z
//// PAUSE-EXAMPLE
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0, 4, -1, 3, 0, 3)), "");
//// RESUME-EXAMPLE
vtkm::Vec3f_64 lower(bounds.X.Min, bounds.Y.Min, bounds.Z.Min);
// lower is [0, -1, 0]
vtkm::Vec3f_64 upper(bounds.X.Max, bounds.Y.Max, bounds.Z.Max);
// upper is [4, 3, 3]
vtkm::Vec3f_64 center = bounds.Center(); // center is [2, 1, 1.5]
////
//// END-EXAMPLE UsingBounds
////
VTKM_TEST_ASSERT(!b1, "Bad non empty.");
VTKM_TEST_ASSERT(b2, "Bad non empty.");
VTKM_TEST_ASSERT(b3, "Bad contains.");
VTKM_TEST_ASSERT(!b4, "Bad contains.");
VTKM_TEST_ASSERT(!b5, "Bad contains.");
VTKM_TEST_ASSERT(b6, "Bad contains.");
VTKM_TEST_ASSERT(b7, "Bad contains.");
VTKM_TEST_ASSERT(!b8, "Bad contains.");
VTKM_TEST_ASSERT(test_equal(lower, vtkm::make_Vec(0, -1, 0)), "");
VTKM_TEST_ASSERT(test_equal(upper, vtkm::make_Vec(4, 3, 3)), "");
VTKM_TEST_ASSERT(test_equal(center, vtkm::make_Vec(2.0, 1.0, 1.5)), "");
}
void Test()
{
SimpleVectorTypes();
CreatingVectorTypes();
VectorOperations();
EquilateralTriangle();
UsingVecCAndVecVariable();
UsingRange();
UsingBounds();
}
} // anonymous namespace
int GuideExampleCoreDataTypes(int argc, char* argv[])
{
return vtkm::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,652 @@
//============================================================================
// 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/BoundsCompute.h>
#include <vtkm/cont/CellSetPermutation.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/DataSetBuilderRectilinear.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/FieldRangeCompute.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/cont/UncertainCellSet.h>
#include <vtkm/filter/field_conversion/CellAverage.h>
#include <vtkm/Math.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace DataSetCreationNamespace
{
namespace can_convert_example
{
////
//// BEGIN-EXAMPLE UnknownCellSetCanConvert
////
VTKM_CONT vtkm::Id3 Get3DPointDimensions(
const vtkm::cont::UnknownCellSet& unknownCellSet)
{
if (unknownCellSet.CanConvert<vtkm::cont::CellSetStructured<3>>())
{
vtkm::cont::CellSetStructured<3> cellSet;
unknownCellSet.AsCellSet(cellSet);
return cellSet.GetPointDimensions();
}
else if (unknownCellSet.CanConvert<vtkm::cont::CellSetStructured<2>>())
{
vtkm::cont::CellSetStructured<2> cellSet;
unknownCellSet.AsCellSet(cellSet);
vtkm::Id2 dims = cellSet.GetPointDimensions();
return vtkm::Id3{ dims[0], dims[1], 1 };
}
else
{
return vtkm::Id3{ unknownCellSet.GetNumberOfPoints(), 1, 1 };
}
}
////
//// END-EXAMPLE UnknownCellSetCanConvert
////
} // namespace can_convert_example
namespace cast_and_call_for_types_example
{
////
//// BEGIN-EXAMPLE UnknownCellSetCastAndCallForTypes
////
struct Get3DPointDimensionsFunctor
{
template<vtkm::IdComponent Dims>
VTKM_CONT void operator()(const vtkm::cont::CellSetStructured<Dims>& cellSet,
vtkm::Id3& outDims) const
{
vtkm::Vec<vtkm::Id, Dims> pointDims = cellSet.GetPointDimensions();
for (vtkm::IdComponent d = 0; d < Dims; ++d)
{
outDims[d] = pointDims[d];
}
}
VTKM_CONT void operator()(const vtkm::cont::CellSet& cellSet, vtkm::Id3& outDims) const
{
outDims[0] = cellSet.GetNumberOfPoints();
}
};
VTKM_CONT vtkm::Id3 Get3DPointDimensions(
const vtkm::cont::UnknownCellSet& unknownCellSet)
{
vtkm::Id3 dims(1);
unknownCellSet.CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST>(
Get3DPointDimensionsFunctor{}, dims);
return dims;
}
////
//// END-EXAMPLE UnknownCellSetCastAndCallForTypes
////
VTKM_CONT vtkm::Id3 Get3DStructuredPointDimensions(
const vtkm::cont::UnknownCellSet& unknownCellSet)
{
vtkm::Id3 dims;
////
//// BEGIN-EXAMPLE UncertainCellSet
////
using StructuredCellSetList = vtkm::List<vtkm::cont::CellSetStructured<1>,
vtkm::cont::CellSetStructured<2>,
vtkm::cont::CellSetStructured<3>>;
vtkm::cont::UncertainCellSet<StructuredCellSetList> uncertainCellSet(unknownCellSet);
uncertainCellSet.CastAndCall(Get3DPointDimensionsFunctor{}, dims);
////
//// END-EXAMPLE UncertainCellSet
////
return dims;
}
} // namespace cast_and_call_for_types_example
struct MyWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn, FieldOutCell);
using ExecutionSignature = _2(IncidentElementCount);
VTKM_EXEC vtkm::IdComponent operator()(vtkm::IdComponent pointCount) const
{
return pointCount;
}
};
void CreateUniformGrid()
{
std::cout << "Creating uniform grid." << std::endl;
////
//// BEGIN-EXAMPLE CreateUniformGrid
////
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet = dataSetBuilder.Create(vtkm::Id3(101, 101, 26));
////
//// END-EXAMPLE CreateUniformGrid
////
vtkm::Bounds bounds = dataSet.GetCoordinateSystem().GetBounds();
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0, 100, 0, 100, 0, 25)),
"Bad bounds");
vtkm::cont::UnknownCellSet unknownCellSet = dataSet.GetCellSet();
VTKM_TEST_ASSERT(can_convert_example::Get3DPointDimensions(unknownCellSet) ==
vtkm::Id3(101, 101, 26));
VTKM_TEST_ASSERT(cast_and_call_for_types_example::Get3DPointDimensions(
unknownCellSet) == vtkm::Id3(101, 101, 26));
VTKM_TEST_ASSERT(cast_and_call_for_types_example::Get3DStructuredPointDimensions(
unknownCellSet) == vtkm::Id3(101, 101, 26));
vtkm::cont::ArrayHandle<vtkm::IdComponent> outArray;
////
//// BEGIN-EXAMPLE UnknownCellSetResetCellSetList
////
using StructuredCellSetList = vtkm::List<vtkm::cont::CellSetStructured<1>,
vtkm::cont::CellSetStructured<2>,
vtkm::cont::CellSetStructured<3>>;
vtkm::cont::Invoker invoke;
invoke(
MyWorklet{}, unknownCellSet.ResetCellSetList<StructuredCellSetList>(), outArray);
////
//// END-EXAMPLE UnknownCellSetResetCellSetList
////
}
void CreateUniformGridCustomOriginSpacing()
{
std::cout << "Creating uniform grid with custom origin and spacing." << std::endl;
////
//// BEGIN-EXAMPLE CreateUniformGridCustomOriginSpacing
////
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet = dataSetBuilder.Create(vtkm::Id3(101, 101, 26),
vtkm::Vec3f(-50.0, -50.0, -50.0),
vtkm::Vec3f(1.0, 1.0, 4.0));
////
//// END-EXAMPLE CreateUniformGridCustomOriginSpacing
////
vtkm::Bounds bounds = dataSet.GetCoordinateSystem().GetBounds();
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(-50, 50, -50, 50, -50, 50)),
"Bad bounds");
}
void CreateRectilinearGrid()
{
std::cout << "Create rectilinear grid." << std::endl;
////
//// BEGIN-EXAMPLE CreateRectilinearGrid
////
// Make x coordinates range from -4 to 4 with tighter spacing near 0.
std::vector<vtkm::Float32> xCoordinates;
for (vtkm::Float32 x = -2.0f; x <= 2.0f; x += 0.02f)
{
xCoordinates.push_back(vtkm::CopySign(x * x, x));
}
// Make y coordinates range from 0 to 2 with tighter spacing near 2.
std::vector<vtkm::Float32> yCoordinates;
for (vtkm::Float32 y = 0.0f; y <= 4.0f; y += 0.02f)
{
yCoordinates.push_back(vtkm::Sqrt(y));
}
// Make z coordinates rangefrom -1 to 1 with even spacing.
std::vector<vtkm::Float32> zCoordinates;
for (vtkm::Float32 z = -1.0f; z <= 1.0f; z += 0.02f)
{
zCoordinates.push_back(z);
}
vtkm::cont::DataSetBuilderRectilinear dataSetBuilder;
vtkm::cont::DataSet dataSet =
dataSetBuilder.Create(xCoordinates, yCoordinates, zCoordinates);
////
//// END-EXAMPLE CreateRectilinearGrid
////
vtkm::Id numPoints = dataSet.GetCellSet().GetNumberOfPoints();
std::cout << "Num points: " << numPoints << std::endl;
VTKM_TEST_ASSERT(numPoints == 4080501, "Got wrong number of points.");
vtkm::Bounds bounds = dataSet.GetCoordinateSystem().GetBounds();
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(-4, 4, 0, 2, -1, 1)), "Bad bounds");
}
void CreateExplicitGrid()
{
std::cout << "Creating explicit grid." << std::endl;
////
//// BEGIN-EXAMPLE CreateExplicitGrid
////
// Array of point coordinates.
std::vector<vtkm::Vec3f_32> pointCoordinates;
pointCoordinates.push_back(vtkm::Vec3f_32(1.1f, 0.0f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(0.2f, 0.4f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(0.9f, 0.6f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(1.4f, 0.5f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(1.8f, 0.3f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(0.4f, 1.0f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(1.0f, 1.2f, 0.0f));
pointCoordinates.push_back(vtkm::Vec3f_32(1.5f, 0.9f, 0.0f));
// Array of shapes.
std::vector<vtkm::UInt8> shapes;
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
shapes.push_back(vtkm::CELL_SHAPE_QUAD);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
shapes.push_back(vtkm::CELL_SHAPE_POLYGON);
shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
// Array of number of indices per cell.
std::vector<vtkm::IdComponent> numIndices;
numIndices.push_back(3);
numIndices.push_back(4);
numIndices.push_back(3);
numIndices.push_back(5);
numIndices.push_back(3);
// Connectivity array.
std::vector<vtkm::Id> connectivity;
connectivity.push_back(0); // Cell 0
connectivity.push_back(2);
connectivity.push_back(1);
connectivity.push_back(0); // Cell 1
connectivity.push_back(4);
connectivity.push_back(3);
connectivity.push_back(2);
connectivity.push_back(1); // Cell 2
connectivity.push_back(2);
connectivity.push_back(5);
connectivity.push_back(2); // Cell 3
connectivity.push_back(3);
connectivity.push_back(7);
connectivity.push_back(6);
connectivity.push_back(5);
connectivity.push_back(3); // Cell 4
connectivity.push_back(4);
connectivity.push_back(7);
// Copy these arrays into a DataSet.
vtkm::cont::DataSetBuilderExplicit dataSetBuilder;
vtkm::cont::DataSet dataSet =
dataSetBuilder.Create(pointCoordinates, shapes, numIndices, connectivity);
////
//// END-EXAMPLE CreateExplicitGrid
////
vtkm::cont::CellSetExplicit<> cellSet;
dataSet.GetCellSet().AsCellSet(cellSet);
VTKM_TEST_ASSERT(test_equal(cellSet.GetNumberOfPoints(), 8),
"Data set has wrong number of points.");
VTKM_TEST_ASSERT(test_equal(cellSet.GetNumberOfCells(), 5),
"Data set has wrong number of cells.");
vtkm::Bounds bounds = dataSet.GetCoordinateSystem().GetBounds();
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0.2, 1.8, 0.0, 1.2, 0.0, 0.0)),
"Bad bounds");
// Do a simple check of the connectivity by getting the number of cells
// incident on each point. This array is unlikely to be correct if the
// topology got screwed up.
auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl;
auto numCellsPortal = numCellsPerPoint.ReadPortal();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
"Wrong number of cells on point 1");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(2), 4),
"Wrong number of cells on point 2");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(3), 3),
"Wrong number of cells on point 3");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(4), 2),
"Wrong number of cells on point 4");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(5), 2),
"Wrong number of cells on point 5");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(6), 1),
"Wrong number of cells on point 6");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(7), 2),
"Wrong number of cells on point 7");
}
void CreateExplicitGridIterative()
{
std::cout << "Creating explicit grid iteratively." << std::endl;
////
//// BEGIN-EXAMPLE CreateExplicitGridIterative
////
vtkm::cont::DataSetBuilderExplicitIterative dataSetBuilder;
dataSetBuilder.AddPoint(1.1, 0.0, 0.0);
dataSetBuilder.AddPoint(0.2, 0.4, 0.0);
dataSetBuilder.AddPoint(0.9, 0.6, 0.0);
dataSetBuilder.AddPoint(1.4, 0.5, 0.0);
dataSetBuilder.AddPoint(1.8, 0.3, 0.0);
dataSetBuilder.AddPoint(0.4, 1.0, 0.0);
dataSetBuilder.AddPoint(1.0, 1.2, 0.0);
dataSetBuilder.AddPoint(1.5, 0.9, 0.0);
dataSetBuilder.AddCell(vtkm::CELL_SHAPE_TRIANGLE);
dataSetBuilder.AddCellPoint(0);
dataSetBuilder.AddCellPoint(2);
dataSetBuilder.AddCellPoint(1);
dataSetBuilder.AddCell(vtkm::CELL_SHAPE_QUAD);
dataSetBuilder.AddCellPoint(0);
dataSetBuilder.AddCellPoint(4);
dataSetBuilder.AddCellPoint(3);
dataSetBuilder.AddCellPoint(2);
dataSetBuilder.AddCell(vtkm::CELL_SHAPE_TRIANGLE);
dataSetBuilder.AddCellPoint(1);
dataSetBuilder.AddCellPoint(2);
dataSetBuilder.AddCellPoint(5);
dataSetBuilder.AddCell(vtkm::CELL_SHAPE_POLYGON);
dataSetBuilder.AddCellPoint(2);
dataSetBuilder.AddCellPoint(3);
dataSetBuilder.AddCellPoint(7);
dataSetBuilder.AddCellPoint(6);
dataSetBuilder.AddCellPoint(5);
dataSetBuilder.AddCell(vtkm::CELL_SHAPE_TRIANGLE);
dataSetBuilder.AddCellPoint(3);
dataSetBuilder.AddCellPoint(4);
dataSetBuilder.AddCellPoint(7);
vtkm::cont::DataSet dataSet = dataSetBuilder.Create();
////
//// END-EXAMPLE CreateExplicitGridIterative
////
vtkm::cont::UnknownCellSet unknownCells = dataSet.GetCellSet();
////
//// BEGIN-EXAMPLE UnknownCellSetAsCellSet
////
vtkm::cont::CellSetExplicit<> cellSet;
unknownCells.AsCellSet(cellSet);
// This is an equivalent way to get the cell set.
auto cellSet2 = unknownCells.AsCellSet<vtkm::cont::CellSetExplicit<>>();
////
//// END-EXAMPLE UnknownCellSetAsCellSet
////
VTKM_STATIC_ASSERT((std::is_same<decltype(cellSet), decltype(cellSet2)>::value));
VTKM_TEST_ASSERT(cellSet.GetConnectivityArray(vtkm::TopologyElementTagCell{},
vtkm::TopologyElementTagPoint{}) ==
cellSet2.GetConnectivityArray(vtkm::TopologyElementTagCell{},
vtkm::TopologyElementTagPoint{}));
VTKM_TEST_ASSERT(test_equal(cellSet.GetNumberOfPoints(), 8),
"Data set has wrong number of points.");
VTKM_TEST_ASSERT(test_equal(cellSet.GetNumberOfCells(), 5),
"Data set has wrong number of cells.");
vtkm::Bounds bounds = dataSet.GetCoordinateSystem().GetBounds();
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0.2, 1.8, 0.0, 1.2, 0.0, 0.0)),
"Bad bounds");
// Do a simple check of the connectivity by getting the number of cells
// incident on each point. This array is unlikely to be correct if the
// topology got screwed up.
auto numCellsPerPoint = cellSet.GetNumIndicesArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell());
vtkm::cont::printSummary_ArrayHandle(numCellsPerPoint, std::cout);
std::cout << std::endl;
auto numCellsPortal = numCellsPerPoint.ReadPortal();
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(0), 2),
"Wrong number of cells on point 0");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(1), 2),
"Wrong number of cells on point 1");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(2), 4),
"Wrong number of cells on point 2");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(3), 3),
"Wrong number of cells on point 3");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(4), 2),
"Wrong number of cells on point 4");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(5), 2),
"Wrong number of cells on point 5");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(6), 1),
"Wrong number of cells on point 6");
VTKM_TEST_ASSERT(test_equal(numCellsPortal.Get(7), 2),
"Wrong number of cells on point 7");
}
void AddFieldData()
{
std::cout << "Add field data." << std::endl;
////
//// BEGIN-EXAMPLE AddFieldData
////
// Make a simple structured data set.
const vtkm::Id3 pointDimensions(20, 20, 10);
const vtkm::Id3 cellDimensions = pointDimensions - vtkm::Id3(1, 1, 1);
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet = dataSetBuilder.Create(pointDimensions);
// Create a field that identifies points on the boundary.
std::vector<vtkm::UInt8> boundaryPoints;
for (vtkm::Id zIndex = 0; zIndex < pointDimensions[2]; zIndex++)
{
for (vtkm::Id yIndex = 0; yIndex < pointDimensions[1]; yIndex++)
{
for (vtkm::Id xIndex = 0; xIndex < pointDimensions[0]; xIndex++)
{
if ((xIndex == 0) || (xIndex == pointDimensions[0] - 1) || (yIndex == 0) ||
(yIndex == pointDimensions[1] - 1) || (zIndex == 0) ||
(zIndex == pointDimensions[2] - 1))
{
boundaryPoints.push_back(1);
}
else
{
boundaryPoints.push_back(0);
}
}
}
}
dataSet.AddPointField("boundary_points", boundaryPoints);
// Create a field that identifies cells on the boundary.
std::vector<vtkm::UInt8> boundaryCells;
for (vtkm::Id zIndex = 0; zIndex < cellDimensions[2]; zIndex++)
{
for (vtkm::Id yIndex = 0; yIndex < cellDimensions[1]; yIndex++)
{
for (vtkm::Id xIndex = 0; xIndex < cellDimensions[0]; xIndex++)
{
if ((xIndex == 0) || (xIndex == cellDimensions[0] - 1) || (yIndex == 0) ||
(yIndex == cellDimensions[1] - 1) || (zIndex == 0) ||
(zIndex == cellDimensions[2] - 1))
{
boundaryCells.push_back(1);
}
else
{
boundaryCells.push_back(0);
}
}
}
}
dataSet.AddCellField("boundary_cells", boundaryCells);
////
//// END-EXAMPLE AddFieldData
////
}
void CreateCellSetPermutation()
{
std::cout << "Create a cell set permutation" << std::endl;
////
//// BEGIN-EXAMPLE CreateCellSetPermutation
////
// Create a simple data set.
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet originalDataSet = dataSetBuilder.Create(vtkm::Id3(33, 33, 26));
vtkm::cont::CellSetStructured<3> originalCellSet;
originalDataSet.GetCellSet().AsCellSet(originalCellSet);
// Create a permutation array for the cells. Each value in the array refers
// to a cell in the original cell set. This particular array selects every
// 10th cell.
vtkm::cont::ArrayHandleCounting<vtkm::Id> permutationArray(0, 10, 2560);
// Create a permutation of that cell set containing only every 10th cell.
vtkm::cont::CellSetPermutation<vtkm::cont::CellSetStructured<3>,
vtkm::cont::ArrayHandleCounting<vtkm::Id>>
permutedCellSet(permutationArray, originalCellSet);
////
//// END-EXAMPLE CreateCellSetPermutation
////
std::cout << "Num points: " << permutedCellSet.GetNumberOfPoints() << std::endl;
VTKM_TEST_ASSERT(permutedCellSet.GetNumberOfPoints() == 28314,
"Wrong number of points.");
std::cout << "Num cells: " << permutedCellSet.GetNumberOfCells() << std::endl;
VTKM_TEST_ASSERT(permutedCellSet.GetNumberOfCells() == 2560, "Wrong number of cells.");
}
void CreatePartitionedDataSet()
{
std::cout << "Creating partitioned data." << std::endl;
////
//// BEGIN-EXAMPLE CreatePartitionedDataSet
////
// Create two uniform data sets
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet1 = dataSetBuilder.Create(vtkm::Id3(10, 10, 10));
vtkm::cont::DataSet dataSet2 = dataSetBuilder.Create(vtkm::Id3(30, 30, 30));
// Add the datasets to a multi block
vtkm::cont::PartitionedDataSet partitionedData;
partitionedData.AppendPartitions({ dataSet1, dataSet2 });
////
//// END-EXAMPLE CreatePartitionedDataSet
////
VTKM_TEST_ASSERT(partitionedData.GetNumberOfPartitions() == 2,
"Incorrect number of blocks");
}
void QueryPartitionedDataSet()
{
std::cout << "Query on a partitioned data." << std::endl;
vtkm::cont::testing::MakeTestDataSet makeData;
vtkm::cont::PartitionedDataSet partitionedData;
partitionedData.AppendPartitions(
{ makeData.Make2DExplicitDataSet0(), makeData.Make3DExplicitDataSet5() });
////
//// BEGIN-EXAMPLE QueryPartitionedDataSet
////
// Get the bounds of a multi-block data set
vtkm::Bounds bounds = vtkm::cont::BoundsCompute(partitionedData);
// Get the overall min/max of a field named "cellvar"
vtkm::cont::ArrayHandle<vtkm::Range> cellvarRanges =
vtkm::cont::FieldRangeCompute(partitionedData, "cellvar");
// Assuming the "cellvar" field has scalar values, then cellvarRanges has one entry
vtkm::Range cellvarRange = cellvarRanges.ReadPortal().Get(0);
////
//// END-EXAMPLE QueryPartitionedDataSet
////
std::cout << bounds << std::endl;
VTKM_TEST_ASSERT(test_equal(bounds, vtkm::Bounds(0.0, 3.0, 0.0, 4.0, 0.0, 1.0)),
"Bad bounds");
std::cout << cellvarRange << std::endl;
VTKM_TEST_ASSERT(test_equal(cellvarRange, vtkm::Range(0, 130.5)), "Bad range");
}
void FilterPartitionedDataSet()
{
std::cout << "Filter on a partitioned data." << std::endl;
vtkm::cont::testing::MakeTestDataSet makeData;
vtkm::cont::PartitionedDataSet partitionedData;
partitionedData.AppendPartitions(
{ makeData.Make3DUniformDataSet0(), makeData.Make3DUniformDataSet1() });
////
//// BEGIN-EXAMPLE FilterPartitionedDataSet
////
vtkm::filter::field_conversion::CellAverage cellAverage;
cellAverage.SetActiveField("pointvar", vtkm::cont::Field::Association::Points);
vtkm::cont::PartitionedDataSet results = cellAverage.Execute(partitionedData);
////
//// END-EXAMPLE FilterPartitionedDataSet
////
VTKM_TEST_ASSERT(results.GetNumberOfPartitions() == 2, "Incorrect number of blocks.");
}
void Test()
{
CreateUniformGrid();
CreateUniformGridCustomOriginSpacing();
CreateRectilinearGrid();
CreateExplicitGrid();
CreateExplicitGridIterative();
AddFieldData();
CreateCellSetPermutation();
CreatePartitionedDataSet();
QueryPartitionedDataSet();
FilterPartitionedDataSet();
}
} // namespace DataSetCreationNamespace
int GuideExampleDataSetCreation(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(DataSetCreationNamespace::Test, argc, argv);
}

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