Compare commits

...

43 Commits

Author SHA1 Message Date
Mingzhe Li
58e923940d Merge branch 'distributed-contours' into 'master'
Distributed Isosurface extraction from branch decomposition

See merge request vtk/vtk-m!3226
2024-07-09 00:51:53 -04:00
Mingzhe Li
477c8b488f shrinking the length of functions used by CastAndCallForTypes in BranchDecompositionTreeMaker.h 2024-07-08 21:51:39 -07:00
Mingzhe Li
67b200c1d5 split topVolumeBranch data to a separate class; split ComputeTopVolBranchHierarchy into a factory class 2024-07-08 21:14:04 -07:00
Kenneth Moreland
5df372db2b Merge topic 'env-options'
310579b9a Load options from environment variables

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Li-Ta Lo <ollie@lanl.gov>
Merge-request: !3243
2024-07-02 16:31:08 -04:00
Kenneth Moreland
310579b9a7 Load options from environment variables
Some common VTK-m options such as the device and log level could be
specified on the command line but not through environment variables. It is
not always possible to set VTK-m command line options, so environment
variables are added.

Also added documentation to the user's guide about what options are
available and how to set them.
2024-07-02 12:47:34 -04:00
Kenneth Moreland
8a67dea2fa Merge branch 'release-2.2' 2024-07-01 12:22:17 -04:00
Kenneth Moreland
a277e57370 Merge topic 'bench-force-cuda'
6b9df5882 Force CUDA device in performance benchmarks

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3224
2024-07-01 12:22:17 -04:00
Kenneth Moreland
cbddde83aa Merge branch 'release-2.0' into release-2.2 2024-07-01 12:22:17 -04:00
Kenneth Moreland
b4c469196e Merge topic 'bench-force-cuda' into release-2.2
6b9df5882 Force CUDA device in performance benchmarks

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3224
2024-07-01 12:22:17 -04:00
Kenneth Moreland
6376680318 Merge topic 'bench-force-cuda' into release-2.0
6b9df5882 Force CUDA device in performance benchmarks

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3224
2024-07-01 12:22:17 -04:00
Kenneth Moreland
5a3289b8db Merge branch 'release-2.2' 2024-07-01 08:54:02 -04:00
Kenneth Moreland
3f0defc4a5 Merge topic 'guide-unknown-arrays' into release-2.2
9a8638aef Update version, acknowledgements, and other meta information
41a088f6c Add guide chapter on unknown array handle

Acked-by: Kitware Robot <kwrobot@kitware.com>
Reviewed-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3241
2024-07-01 08:54:02 -04:00
Kenneth Moreland
ee0e7d0bfb Merge topic 'guide-unknown-arrays'
9a8638aef Update version, acknowledgements, and other meta information
41a088f6c Add guide chapter on unknown array handle

Acked-by: Kitware Robot <kwrobot@kitware.com>
Reviewed-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3241
2024-07-01 08:54:02 -04:00
Kenneth Moreland
6b9df58824 Force CUDA device in performance benchmarks 2024-06-28 15:12:22 -04:00
Kenneth Moreland
9a8638aef2 Update version, acknowledgements, and other meta information 2024-06-28 13:42:23 -04:00
Kenneth Moreland
41a088f6ce Add guide chapter on unknown array handle 2024-06-28 13:42:23 -04:00
Kenneth Moreland
f610044d79 Merge topic 'split-contour-bench-2-1' into release-2.0
6f5f65487 Split the contour benchmark into structured/unstructured

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3239
2024-06-28 11:10:45 -04:00
Kenneth Moreland
cb07d8400c Merge branch 'release-2.0' into release 2024-06-28 11:10:45 -04:00
Kenneth Moreland
fc570a75a5 Merge branch 'release' into master 2024-06-28 11:10:45 -04:00
Vicente Bolea
9c0a3aef31 Merge topic 'update-rocm'
c6f0e3698 ci: update kokkos hip to 6.1, ubuntu 2204

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Kenneth Moreland <morelandkd@ornl.gov>
Merge-request: !3237
2024-06-27 14:21:15 -04:00
Kenneth Moreland
6f5f654878 Split the contour benchmark into structured/unstructured
We've been having problems with PerformanceTestBenchContour. In the last
few iteration, the runtime goes way up. We cannot find any reason for
this in the source code. There don't appear to be any particular
problems with memory or tables. The best we can figure is an issue with
the device hardware in the container.

The easy solution should be to break the benchmark into smaller peices
to avoid the problem.
2024-06-26 17:47:27 -04:00
Vicente Bolea
b6a0e4d79b Merge topic 'backport-3233' into release-2.0
638d18356 fix: perftest upload
1078d7dfb Revert "ci: fix perftest uploading"

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Kenneth Moreland <morelandkd@ornl.gov>
Merge-request: !3235
2024-06-26 17:46:45 -04:00
Vicente Bolea
743a7c3ac4 Merge branch 'release-2.0' into release 2024-06-26 17:46:45 -04:00
Vicente Bolea
726bd0b551 Merge branch 'release' into master 2024-06-26 17:46:45 -04:00
Vicente Adolfo Bolea Sanchez
c6f0e36986 ci: update kokkos hip to 6.1, ubuntu 2204 2024-06-26 16:31:25 -04:00
Vicente Bolea
f1eac04f72 Merge branch 'release-2.1' 2024-06-25 12:14:43 -04:00
Vicente Bolea
d6914b6010 Merge topic 'update-to-2.2.0'
c1c7b0df5 release: 2.2.0-rc1 release notes
f2eefbd5c release: update version and License

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Kenneth Moreland <morelandkd@ornl.gov>
Merge-request: !3238
2024-06-25 12:14:43 -04:00
Vicente Adolfo Bolea Sanchez
67a4def093 2.2.0-rc1 is our 17th official release of VTK-m.
The major changes to VTK-m from (previous release) can be found in:
  docs/changelog/2.2.0/release-notes.md
2024-06-24 17:43:01 -04:00
Vicente Adolfo Bolea Sanchez
c1c7b0df50 release: 2.2.0-rc1 release notes 2024-06-24 17:41:03 -04:00
Vicente Adolfo Bolea Sanchez
f2eefbd5ca release: update version and License 2024-06-24 17:22:14 -04:00
Kenneth Moreland
a0db7c3f5b Merge topic 'split-contour-bench'
4c392f9b5 Split the contour benchmark into structured/unstructured

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3229
2024-06-24 12:58:05 -04:00
Kenneth Moreland
d7890b3493 Merge branch 'release-2.1' 2024-06-24 09:05:49 -04:00
Kenneth Moreland
4335e43e50 Merge topic 'allow-backward-compatibility'
b2997bcbe Support backward compatibility in CMake package

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3234
2024-06-24 09:05:49 -04:00
Kenneth Moreland
cac8baa055 Merge topic 'allow-backward-compatibility' into release-2.1
b2997bcbe Support backward compatibility in CMake package

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3234
2024-06-24 09:05:48 -04:00
Vicente Adolfo Bolea Sanchez
638d183567 fix: perftest upload
(cherry picked from commit 76ddf7a5b2836cf4153e36f28dd2675f5ef8a735)
2024-06-21 16:50:11 -04:00
Vicente Adolfo Bolea Sanchez
1078d7dfb4 Revert "ci: fix perftest uploading"
This reverts commit 31b8b2faf90a79e069761b12deac8525cd4c0aa1.

(cherry picked from commit cdd3a55f61850c4438a0b0f890bc6e3f11c641fb)
2024-06-21 16:50:07 -04:00
Kenneth Moreland
b2997bcbe8 Support backward compatibility in CMake package
VTK-m development is in a mode where backward compatibility should be
maintained between minor versions of the software. (You may get deprecation
warnings, but things should still work.) To match this behavior, the
generated CMake package now supports finding versions with the same major
release and the same or newer minor release. For example, if an external
program does this

``` cmake
find_package(VTKm 2.1 REQUIRED)
```

then CMake will link to 2.1 (of course) as well as newer minor releases
(e.g., 2.2, 2.3, etc.). It will not, however, match older versions (e.g.,
2.0, 1.9), nor will it match any version after the next major release
(e.g., 3.0).
2024-06-21 15:28:42 -04:00
Kenneth Moreland
4c392f9b58 Split the contour benchmark into structured/unstructured
We've been having problems with PerformanceTestBenchContour. In the last
few iteration, the runtime goes way up. We cannot find any reason for
this in the source code. There don't appear to be any particular
problems with memory or tables. The best we can figure is an issue with
the device hardware in the container.

The easy solution should be to break the benchmark into smaller peices
to avoid the problem.
2024-06-21 14:48:17 -04:00
Kenneth Moreland
c6ad00aefd Merge topic 'guide-fancy-arrays'
3e6963092 Add guide chapter on fancy array handles

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Vicente Bolea <vicente.bolea@kitware.com>
Merge-request: !3231
2024-06-21 14:45:38 -04:00
Vicente Bolea
46d872d7c2 Merge topic 'fix-uploading-vtkm-perf-test'
76ddf7a5b fix: perftest upload
cdd3a55f6 Revert "ci: fix perftest uploading"

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Kenneth Moreland <morelandkd@ornl.gov>
Merge-request: !3233
2024-06-21 14:32:34 -04:00
Vicente Adolfo Bolea Sanchez
76ddf7a5b2 fix: perftest upload 2024-06-21 12:32:29 -04:00
Vicente Adolfo Bolea Sanchez
cdd3a55f61 Revert "ci: fix perftest uploading"
This reverts commit 31b8b2faf90a79e069761b12deac8525cd4c0aa1.
2024-06-21 12:31:24 -04:00
Kenneth Moreland
3e69630925 Add guide chapter on fancy array handles 2024-06-05 17:51:14 -04:00
99 changed files with 4156 additions and 1126 deletions

@ -69,8 +69,8 @@
extends:
- .docker_image
.ubuntu2004_hip_kokkos: &ubuntu2004_hip_kokkos
image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20230220"
.ubuntu2204_hip_kokkos: &ubuntu2204_hip_kokkos
image: "kitware/vtkm:ci-ubuntu2204_hip_kokkos-20240625"
extends:
- .docker_image
@ -245,4 +245,5 @@ include:
- local: '/.gitlab/ci/ubuntu1604.yml'
- local: '/.gitlab/ci/ubuntu1804.yml'
- local: '/.gitlab/ci/ubuntu2004.yml'
- local: '/.gitlab/ci/ubuntu2204.yml'
- local: '/.gitlab/ci/windows10.yml'

@ -10,7 +10,7 @@
##
##=============================================================================
FROM rocm/dev-ubuntu-20.04
FROM rocm/dev-ubuntu-22.04
LABEL maintainer "Vicente Adolfo Bolea Sanchez<vicente.bolea@gmail.com>"
# Base dependencies for building VTK-m projects
@ -58,11 +58,22 @@ ENV PATH "/opt/cmake/bin:${PATH}"
ENV CMAKE_PREFIX_PATH "/opt/rocm/lib/cmake:/opt/rocm/lib:${CMAKE_PREFIX_PATH}"
ENV CMAKE_GENERATOR "Ninja"
# Build and install Kokkos
ARG KOKKOS_VERSION=3.7.01
ENV KOKKOS_VERSION=3.7.01
COPY kokkos_cmake_config.cmake kokkos_cmake_config.cmake
RUN curl -L https://github.com/kokkos/kokkos/archive/refs/tags/$KOKKOS_VERSION.tar.gz | tar -xzf - && \
cmake -S kokkos-$KOKKOS_VERSION -B build -C kokkos_cmake_config.cmake && \
cmake -S kokkos-$KOKKOS_VERSION -B build -C kokkos_cmake_config.cmake \
-DCMAKE_PREFIX_INSTALL=/opt/kokkos/$KOKKOS_VERSION \
-DKokkos_ARCH_VEGA900=ON && \
cmake --build build -v && \
cmake --install build && \
rm -rf build kokkos-$KOKKOS_VERSION
ENV KOKKOS_VERSION=4.3.01
COPY kokkos_cmake_config.cmake kokkos_cmake_config.cmake
RUN curl -L https://github.com/kokkos/kokkos/archive/refs/tags/$KOKKOS_VERSION.tar.gz | tar -xzf - && \
cmake -S kokkos-$KOKKOS_VERSION -B build -C kokkos_cmake_config.cmake \
-DCMAKE_PREFIX_INSTALL=/opt/kokkos/$KOKKOS_VERSION \
-DKokkos_ARCH_VEGA906=ON && \
cmake --build build -v && \
cmake --install build && \
rm -rf build kokkos-$KOKKOS_VERSION

@ -9,13 +9,10 @@
##============================================================================
set(CMAKE_BUILD_TYPE "release" CACHE STRING "")
set(CMAKE_INSTALL_PREFIX /opt/kokkos CACHE PATH "")
set(CMAKE_C_COMPILER /opt/rocm/llvm/bin/clang CACHE FILEPATH "")
set(CMAKE_CXX_COMPILER /opt/rocm/llvm/bin/clang++ CACHE FILEPATH "")
set(CMAKE_CXX_STANDARD "14" CACHE STRING "")
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "")
set(Kokkos_ENABLE_SERIAL ON CACHE BOOL "")
set(Kokkos_ARCH_VEGA900 ON CACHE BOOL "")
set(Kokkos_ENABLE_HIP ON CACHE BOOL "")
set(Kokkos_ENABLE_HIP_RELOCATABLE_DEVICE_CODE OFF CACHE BOOL "")

@ -196,7 +196,7 @@ test:ubuntu1804_clang8:
# Build on ubuntu1804 with kokkos and test on ubuntu1804
# Uses CUDA 11
build:ubuntu1804_kokkos:
build:ubuntu1804_kokkos37:
tags:
- build
- vtkm
@ -212,7 +212,7 @@ build:ubuntu1804_kokkos:
CMAKE_BUILD_TYPE: Release
VTKM_SETTINGS: "benchmarks+kokkos+turing+64bit_floats+shared"
test:ubuntu1804_kokkos:
test:ubuntu1804_kokkos37:
tags:
- test
- vtkm
@ -225,9 +225,9 @@ test:ubuntu1804_kokkos:
- .cmake_test_linux
- .run_automatically
dependencies:
- build:ubuntu1804_kokkos
- build:ubuntu1804_kokkos37
needs:
- build:ubuntu1804_kokkos
- build:ubuntu1804_kokkos37
build:ubuntu1804_cuda_perftest:
tags:
@ -261,6 +261,7 @@ test:ubuntu1804_cuda_perftest:
variables:
TEST_INCLUSIONS: "PerformanceTest"
VTKm_PERF_REMOTE_URL: "https://vbolea:$VTKM_BENCH_RECORDS_TOKEN@gitlab.kitware.com/vbolea/vtk-m-benchmark-records.git"
VTKm_PERF_BENCH_DEVICE: "cuda"
VTKm_PERF_ALPHA: "0.05"
VTKm_PERF_REPETITIONS: "10"
VTKm_PERF_DIST: "t"

@ -10,7 +10,7 @@
##
##=============================================================================
build:ubuntu2004_kokkos:
build:ubuntu2004_kokkos37:
tags:
- build
- vtkm
@ -25,7 +25,7 @@ build:ubuntu2004_kokkos:
CMAKE_PREFIX_PATH: "/opt/anari"
VTKM_SETTINGS: "kokkos+shared+64bit_floats+rendering+anari"
test:ubuntu2004_kokkos:
test:ubuntu2004_kokkos37:
tags:
- test
- vtkm
@ -36,55 +36,6 @@ test:ubuntu2004_kokkos:
- .cmake_test_linux
- .run_automatically
dependencies:
- build:ubuntu2004_kokkos
- build:ubuntu2004_kokkos37
needs:
- build:ubuntu2004_kokkos
build:ubuntu2004_hip_kokkos:
tags:
- vtkm
- docker
- linux-x86_64
- radeon
extends:
- .ubuntu2004_hip_kokkos
- .cmake_build_linux
- .run_automatically
variables:
CMAKE_BUILD_TYPE: "RelWithDebInfo"
VTKM_SETTINGS: "benchmarks+kokkos+hip+no_rendering+ccache"
CMAKE_PREFIX_PATH: "/opt/rocm/lib/cmake"
LD_LIBRARY_PATH: "/opt/rocm/lib"
CMAKE_HIP_COMPILER: "/opt/rocm/llvm/bin/clang++"
Kokkos_CXX_COMPILER: "/opt/rocm/llvm/bin/clang++"
CMAKE_HIP_ARCHITECTURES: "gfx900"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_BASEDIR: "$CI_PROJECT_DIR"
CCACHE_COMPILERCHECK: "content"
CCACHE_NOHASHDIR: "true"
CCACHE_RESHARE: "true"
after_script:
- ccache -v -s
- ccache -z
test:ubuntu2004_hip_kokkos:
tags:
- vtkm
- docker
- linux-x86_64
- radeon
extends:
- .ubuntu2004_hip_kokkos
- .cmake_test_linux
- .run_upstream_branches
variables:
CTEST_MAX_PARALLELISM: 1
CTEST_EXCLUSIONS: "UnitTestWorkletParticleAdvection"
dependencies:
- build:ubuntu2004_hip_kokkos
needs:
- build:ubuntu2004_hip_kokkos
timeout: 3 hours
- build:ubuntu2004_kokkos37

85
.gitlab/ci/ubuntu2204.yml Normal file

@ -0,0 +1,85 @@
##=============================================================================
##
## 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.
##
##=============================================================================
.kokkos_rocm_vars: &kokkos_rocm_vars
variables:
CCACHE_BASEDIR: "$CI_PROJECT_DIR"
CCACHE_COMPILERCHECK: "content"
# -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it
CCACHE_IGNOREOPTIONS: "-isystem=*"
CCACHE_NOHASHDIR: "true"
CCACHE_RESHARE: "true"
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_HIP_COMPILER: "/opt/rocm/llvm/bin/clang++"
Kokkos_CXX_COMPILER: "/opt/rocm/llvm/bin/clang++"
LD_LIBRARY_PATH: "/opt/rocm/lib"
CXX: "hipcc"
build:ubuntu2204_hip_kokkos37:
tags:
- vtkm
- docker
- linux-x86_64
- radeon
extends:
- .ubuntu2204_hip_kokkos
- .cmake_build_linux
- .kokkos_rocm_vars
- .run_automatically
variables:
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_HIP_ARCHITECTURES: "gfx900"
Kokkos_DIR: "/opt/kokkos/3.7.01/"
VTKM_SETTINGS: "benchmarks+kokkos+hip+no_rendering+ccache"
after_script:
- ccache -v -s
- ccache -z
test:ubuntu2204_hip_kokkos37:
tags:
- vtkm
- docker
- linux-x86_64
- radeon
extends:
- .ubuntu2204_hip_kokkos
- .cmake_test_linux
- .run_upstream_branches
variables:
CTEST_MAX_PARALLELISM: 1
CTEST_EXCLUSIONS: "UnitTestWorkletParticleAdvection"
dependencies:
- build:ubuntu2204_hip_kokkos37
needs:
- build:ubuntu2204_hip_kokkos37
timeout: 3 hours
build:ubuntu2204_hip_kokkos43:
tags:
- vtkm
- docker
- linux-x86_64
- radeon
extends:
- .ubuntu2204_hip_kokkos
- .cmake_build_linux
- .kokkos_rocm_vars
- .run_automatically
variables:
CMAKE_BUILD_TYPE: "RelWithDebInfo"
CMAKE_HIP_ARCHITECTURES: "gfx906"
Kokkos_DIR: "/opt/kokkos/4.3.01/"
VTKM_SETTINGS: "benchmarks+kokkos+hip+no_rendering+ccache"
after_script:
- ccache -v -s
- ccache -z

@ -76,6 +76,14 @@ function(add_benchmark_test benchmark)
set(VTKm_PERF_COMPARE_JSON "${CMAKE_BINARY_DIR}/$ENV{CI_COMMIT_SHA}_${VTKm_PERF_NAME}.json")
endif()
# Only upload when we are inside a CI build and in master. We need to check
# if VTKM_BENCH_RECORDS_TOKEN is either defined or non-empty, the reason is
# that in Gitlab CI Variables for protected branches are also defined in MR
# from forks, however, they are empty.
if (DEFINED ENV{VTKM_BENCH_RECORDS_TOKEN} AND NOT $ENV{VTKM_BENCH_RECORDS_TOKEN} STREQUAL "")
set(enable_upload TRUE)
endif()
set(test_name "PerformanceTest${VTKm_PERF_NAME}")
###TEST INVOKATIONS##########################################################
@ -117,12 +125,7 @@ function(add_benchmark_test benchmark)
-P "${VTKm_SOURCE_DIR}/CMake/testing/VTKmPerformanceTestReport.cmake"
)
# Only upload when we are inside a CI build and in master. We need to check
# if VTKM_BENCH_RECORDS_TOKEN is non-empty, the reason is that in Gitlab CI
# Variables for protected branches are also defined in MR from forks,
# however, they are empty.
if ($ENV{VTKM_BENCH_RECORDS_TOKEN})
if (enable_upload)
add_test(NAME "${test_name}Upload"
COMMAND ${CMAKE_COMMAND}
"-DVTKm_PERF_REPO=${VTKm_PERF_REPO}"

@ -352,7 +352,7 @@ configure_package_config_file(
write_basic_package_version_file(
${VTKm_BUILD_CMAKE_BASE_DIR}/${VTKm_INSTALL_CONFIG_DIR}/VTKmConfigVersion.cmake
VERSION ${VTKm_VERSION}
COMPATIBILITY ExactVersion )
COMPATIBILITY SameMajorVersion )
#-----------------------------------------------------------------------------
# Add subdirectories

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

@ -81,6 +81,8 @@ Optional dependencies are:
+ Kokkos Device Adapter
+ [Kokkos](https://kokkos.github.io/) 3.7+
+ CXX env variable or CMAKE_CXX_COMPILER should be set to
hipcc when using Kokkos device adapter with HIP (ROCM>=6).
+ CUDA Device Adapter
+ [Cuda Toolkit 9.2, >= 10.2](https://developer.nvidia.com/cuda-toolkit)
+ Note CUDA >= 10.2 is required on Windows

@ -81,10 +81,14 @@ if(VTKm_ENABLE_PERFORMANCE_TESTING)
REGEX BenchTetrahedralize
)
add_benchmark_test(BenchmarkFilters
NAME BenchContour
NAME BenchContourStructured
REGEX
BenchContour/IsStructuredDataSet:1/NIsoVals:12/MergePts:1/GenNormals:0.*/MultiPartitioned:0
BenchContour/IsStructuredDataSet:1/NIsoVals:12/MergePts:0/GenNormals:1/FastNormals:1.*/MultiPartitioned:0
)
add_benchmark_test(BenchmarkFilters
NAME BenchContourUnstructured
REGEX
BenchContour/IsStructuredDataSet:0/NIsoVals:12/MergePts:1/GenNormals:0.*/MultiPartitioned:0
BenchContour/IsStructuredDataSet:0/NIsoVals:12/MergePts:0/GenNormals:1/FastNormals:1.*/MultiPartitioned:0
)

@ -0,0 +1,421 @@
VTK-m 2.2.0 Release Notes
=======================
# Table of Contents
1. [Core](#Core)
- Enable non-finite values with Intel compiler.
2. [ArrayHandle](#ArrayHandle)
- Add `GetNumberOfComponentsFlat` method to `ArrayHandle`.
- Support `Fill` for `ArrayHandleStride`.
- Added support for component extraction from ArrayHandleConstant better.
- Store constant AMR arrays with less memory.
- Improved = operators in VecFromPortal.
- Deprecate the GetCounts() method in Keys objects.
- Enable new instances of unknown arrays with dynamic sizes.
3. [Filters and Worklets](#Filters_and_Worklets)
- Consolidate WarpScalar and WarpVector filter.
- Adding MergeDataSets filter.
- Fix bug with ExtractGeometry filter.
- New Isosurface Uncertainty Visualization Analysis filter.
- Deprecated `vtkm::filter::FilterField`.
- Adding SliceMultiple filter.
- Constructors for mesh info classes updated to conform with other filters.
- Allow floating-point isovalues for contours of integer fields.
4. [Control Environment](#Control_Environment)
5. [Execution Environment](#Execution_Environment)
- AtomicArrayExecutionObject: Allow order of atomic operations.
- Disable Thrust patch that is no longer needed in modern Thrust.
- Add hints to device adapter scheduler.
6. [Build](#Build)
- Support backward compatibility in CMake package.
- Fix issue with union placeholder on Intel compiler.
- Fix old cuda atomics.
7. [Others](#Others)
- Avoid floating point exceptions in rendering code.
- Added VTK-m's user guide into the source code.
- Fix crash when CUDA device is disabled.
# Core
## Enable non-finite values with Intel compiler
The Intel compiler by default turns on an optimization that assumes that
all floating point values are finite. This breaks any ligitimate uses of
non-finite values including checking values with functions like `isnan`
and `isinf`. Turn off this feature for the intel compiler.
# ArrayHandle
## 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.
## 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.
## Added support for component extraction from ArrayHandleConstant better
Previously, `ArrayHandleConstant` did not really support component
extraction. Instead, it let a fallback operation create a full array on
the CPU.
Component extraction is now quite efficient for `ArrayHandleConstant`. It
creates a basic `ArrayHandle` with one entry and sets a modulo on the
`ArrayHandleStride` to access that value for all indices.
## 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.
## Improved = operators in VecFromPortal
Previously, `VecFromPortal` could only be set to a standard `Vec`.
However, because this is a `Vec`-like object with a runtime-size, it is
hard to do general arithmetic on it. It is easier to do in place so
there is some place to put the result. To make it easier to operate on
this as the result of other `Vec`-likes, extend the operators like `+=`,
`*=`, etc to support this.
## 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.
## 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`.
# Filters and Worklets
## 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.
## 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.
## Fix bug with ExtractGeometry filter
The `ExtractGeometry` filter was outputing datasets containing
`CellSetPermutation` as the representation for the cells. Although this is
technically correct and a very fast implementation, it is essentially
useless. The problem is that any downstream processing will have to know
that the data has a `CellSetPermutation`. None do (because the permutation
can be on any other cell set type, which creates an explosion of possible
cell types).
Like was done with `Threshold` a while ago, this problem is fixed by deep
copying the result into a `CellSetExplicit`. This behavior is consistent
with VTK.
## 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.
## 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`.
## 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.
## 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.
## 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.
# Control Environment
# Execution Environment
## AtomicArrayExecutionObject: Allow order of atomic operations
AtomicArrayExecutionObject now allows order of atomic operations for Get/Set/Add/CompareExchange.
## Disable Thrust patch that is no longer needed in modern Thrust
There is a Thrust patch that works around an issue in Thrust 1.9.4
(https://github.com/NVIDIA/thrust/issues/972). The underlying issue
should be fixed in recent versions. In recent versions of CUDA, the patch
breaks (https://gitlab.kitware.com/vtk/vtk-m/-/issues/818).
This change fixes the problem by disabling the patch where it is not
needed.
## 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.
# Build
## Support backward compatibility in CMake package
VTK-m development is in a mode where backward compatibility should be
maintained between minor versions of the software. (You may get deprecation
warnings, but things should still work.) To match this behavior, the
generated CMake package now supports finding versions with the same major
release and the same or newer minor release. For example, if an external
program does this
``` cmake
find_package(VTKm 2.1 REQUIRED)
```
then CMake will link to 2.1 (of course) as well as newer minor releases
(e.g., 2.2, 2.3, etc.). It will not, however, match older versions (e.g.,
2.0, 1.9), nor will it match any version after the next major release
(e.g., 3.0).
## 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`.
## Fix old cuda atomics
There are some overloads for atomic adds of floating point numbers for
older versions of cuda that do not include them directly. These were
misnamed and thus not properly overloading the generic implementation.
This caused compile errors with older versions of cuda.
## Fix crash when CUDA device is disabled
There was an issue where if VTK-m was compiled with CUDA support but then
run on a computer where no CUDA device was available, an inappropriate
exception was thrown (instead of just disabling the device). The
initialization code should now properly check for the existance of a CUDA
device.
# Others
## 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.
## 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.

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

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

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

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

@ -1,9 +0,0 @@
# Added support for component extraction from ArrayHandleConstant better
Previously, `ArrayHandleConstant` did not really support component
extraction. Instead, it let a fallback operation create a full array on
the CPU.
Component extraction is now quite efficient for `ArrayHandleConstant`. It
creates a basic `ArrayHandle` with one entry and sets a modulo on the
`ArrayHandleStride` to access that value for all indices.

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

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

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

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

@ -1,12 +0,0 @@
# 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,9 @@
## Load options from environment variables
Some common VTK-m options such as the device and log level could be
specified on the command line but not through environment variables. It is
not always possible to set VTK-m command line options, so environment
variables are added.
Also added documentation to the user's guide about what options are
available and how to set them.

@ -1,13 +0,0 @@
# Fix bug with ExtractGeometry filter
The `ExtractGeometry` filter was outputing datasets containing
`CellSetPermutation` as the representation for the cells. Although this is
technically correct and a very fast implementation, it is essentially
useless. The problem is that any downstream processing will have to know
that the data has a `CellSetPermutation`. None do (because the permutation
can be on any other cell set type, which creates an explosion of possible
cell types).
Like was done with `Threshold` a while ago, this problem is fixed by deep
copying the result into a `CellSetExplicit`. This behavior is consistent
with VTK.

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

@ -1,6 +0,0 @@
# Fix old cuda atomics
There are some overloads for atomic adds of floating point numbers for
older versions of cuda that do not include them directly. These were
misnamed and thus not properly overloading the generic implementation.
This caused compile errors with older versions of cuda.

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

@ -1,6 +0,0 @@
# Enable non-finite values with Intel compiler
The Intel compiler by default turns on an optimization that assumes that
all floating point values are finite. This breaks any ligitimate uses of
non-finite values including checking values with functions like `isnan`
and `isinf`. Turn off this feature for the intel compiler.

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

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

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

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

@ -1,9 +0,0 @@
# Disable Thrust patch that is no longer needed in modern Thrust
There is a Thrust patch that works around an issue in Thrust 1.9.4
(https://github.com/NVIDIA/thrust/issues/972). The underlying issue
should be fixed in recent versions. In recent versions of CUDA, the patch
breaks (https://gitlab.kitware.com/vtk/vtk-m/-/issues/818).
This change fixes the problem by disabling the patch where it is not
needed.

@ -1,7 +0,0 @@
# Fix crash when CUDA device is disabled
There was an issue where if VTK-m was compiled with CUDA support but then
run on a computer where no CUDA device was available, an inappropriate
exception was thrown (instead of just disabling the device). The
initialization code should now properly check for the existance of a CUDA
device.

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

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

@ -1,8 +0,0 @@
# Improved = operators in VecFromPortal
Previously, `VecFromPortal` could only be set to a standard `Vec`.
However, because this is a `Vec`-like object with a runtime-size, it is
hard to do general arithmetic on it. It is easier to do in place so
there is some place to put the result. To make it easier to operate on
this as the result of other `Vec`-likes, extend the operators like `+=`,
`*=`, etc to support this.

@ -90,5 +90,8 @@ Sandia National Laboratories is a multimission laboratory managed and operated b
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.
This work was supported in part by the U.S. Department of Energy (DOE) RAPIDS SciDAC project under contract number DE-AC05-00OR22725 and by the Exascale Computing Project (17-SC-20-SC), a collaborative effort of the U.S. Department of Energy Office of Science and the National Nuclear Security Administration.
This research used resources of the Oak Ridge Leadership Computing Facility at the Oak Ridge National Laboratory, which is supported by the Office of Science of the U.S. Department of Energy under Contract No. DE-AC05-00OR22725.
This research used resources of the Argonne Leadership Computing Facility, a U.S. Department of Energy (DOE) Office of Science user facility at Argonne National Laboratory and is based on research supported by the U.S. DOE Office of Science-Advanced Scientific Computing Research Program, under Contract No. DE-AC02-06CH11357.

@ -636,9 +636,7 @@ This is most typically used with C++ run-time type information to convert a run-
.. 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.
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 :chapref:`unknown-array-handle:Unknown Array Handles`.
.. load-example:: ListForEach
:file: GuideExampleLists.cxx

@ -72,9 +72,7 @@ The filter implementation can get the appropriate field to operate on using the
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.
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 :chapref:`unknown-array-handle:Unknown Array Handles`, but the :class:`vtkm::filter::Filter` contains some convenience functions to simplify this.
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.

@ -20,7 +20,7 @@ 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@'
release = '@VTKm_VERSION_MAJOR@.@VTKm_VERSION_MINOR@'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@ -76,8 +76,8 @@ 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
.. |report-year| replace:: 2024
.. |report-number| replace:: ORNL/TM-2024/3443
'''
breathe_projects = { 'vtkm': '@doxygen_xml_output_dir@' }

@ -365,8 +365,7 @@ The third array identifies an offset into the second array where the point indic
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)
See the documentation for :class:`vtkm::cont::ArrayHandleGroupVecVariable` in :secref:`fancy-array-handles:Grouped Vector Arrays` for examples of using :func:`vtkm::cont::ConvertNumComponentsToOffsets`.
:class:`vtkm::cont::CellSetExplicit` is a powerful representation for a cell set
because it can represent an arbitrary collection of cells. However, because

@ -10,7 +10,19 @@
set(examples
GuideExampleArrayHandle.cxx
GuideExampleArrayHandleCast.cxx
GuideExampleArrayHandleCompositeVector.cxx
GuideExampleArrayHandleConstant.cxx
GuideExampleArrayHandleCoordinateSystems.cxx
GuideExampleArrayHandleCounting.cxx
GuideExampleArrayHandleExtractComponent.cxx
GuideExampleArrayHandleGroupVec.cxx
GuideExampleArrayHandlePermutation.cxx
GuideExampleArrayHandleRandom.cxx
GuideExampleArrayHandleRuntimeVec.cxx
GuideExampleArrayHandleSwizzle.cxx
GuideExampleArrayHandleView.cxx
GuideExampleArrayHandleZip.cxx
GuideExampleCellShapes.cxx
GuideExampleColorTables.cxx
GuideExampleCoreDataTypes.cxx
@ -28,6 +40,7 @@ set(examples
GuideExampleTuple.cxx
)
set(examples_device
GuideExampleArrayHandleDiscard.cxx
GuideExampleCellEdgesFaces.cxx
GuideExampleCellLocator.cxx
GuideExampleCellOperations.cxx

@ -0,0 +1,83 @@
//============================================================================
// 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/ArrayHandleCast.h>
#include <vector>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename OriginalType, typename ArrayHandleType>
void CheckArray(const ArrayHandleType array)
{
vtkm::Id length = array.GetNumberOfValues();
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == length, "Portal has wrong size.");
for (vtkm::Id index = 0; index < length; index++)
{
VTKM_TEST_ASSERT(test_equal(portal.Get(index), TestValue(index, OriginalType())),
"Array has wrong value.");
VTKM_TEST_ASSERT(
!test_equal(portal.Get(index),
TestValue(index, typename ArrayHandleType::ValueType())),
"Array has wrong value.");
}
}
////
//// BEGIN-EXAMPLE ArrayHandleCast
////
template<typename T>
VTKM_CONT void Foo(const std::vector<T>& inputData)
{
vtkm::cont::ArrayHandle<T> originalArray =
vtkm::cont::make_ArrayHandle(inputData, vtkm::CopyFlag::On);
vtkm::cont::ArrayHandleCast<vtkm::Float64, vtkm::cont::ArrayHandle<T>> castArray(
originalArray);
////
//// END-EXAMPLE ArrayHandleCast
////
CheckArray<T>(castArray);
CheckArray<T>(
////
//// BEGIN-EXAMPLE MakeArrayHandleCast
////
vtkm::cont::make_ArrayHandleCast<vtkm::Float64>(originalArray)
////
//// END-EXAMPLE MakeArrayHandleCast
////
);
}
void Test()
{
const std::size_t ARRAY_SIZE = 50;
std::vector<vtkm::Int32> inputData(ARRAY_SIZE);
for (std::size_t index = 0; index < ARRAY_SIZE; index++)
{
inputData[index] = TestValue(vtkm::Id(index), vtkm::Int32());
}
Foo(inputData);
}
} // anonymous namespace
int GuideExampleArrayHandleCast(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,106 @@
//============================================================================
// 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/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(ArrayHandleType array)
{
vtkm::cont::printSummary_ArrayHandle(array, std::cout);
std::cout << std::endl;
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
// [(0,3,2,0), (1,1,7,0), (2,4,1,0), (3,1,8,0), (4,5,2,0)].
VTKM_TEST_ASSERT(test_equal(portal.Get(0), vtkm::make_Vec(0, 3, 2, 0)),
"Bad value in array.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), vtkm::make_Vec(1, 1, 7, 0)),
"Bad value in array.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), vtkm::make_Vec(2, 4, 1, 0)),
"Bad value in array.");
VTKM_TEST_ASSERT(test_equal(portal.Get(3), vtkm::make_Vec(3, 1, 8, 0)),
"Bad value in array.");
}
void ArrayHandleCompositeVectorBasic()
{
////
//// BEGIN-EXAMPLE ArrayHandleCompositeVectorBasic
////
// Create an array with [0, 1, 2, 3, 4]
using ArrayType1 = vtkm::cont::ArrayHandleIndex;
ArrayType1 array1(5);
// Create an array with [3, 1, 4, 1, 5]
using ArrayType2 = vtkm::cont::ArrayHandle<vtkm::Id>;
ArrayType2 array2;
array2.Allocate(5);
ArrayType2::WritePortalType arrayPortal2 = array2.WritePortal();
arrayPortal2.Set(0, 3);
arrayPortal2.Set(1, 1);
arrayPortal2.Set(2, 4);
arrayPortal2.Set(3, 1);
arrayPortal2.Set(4, 5);
// Create an array with [2, 7, 1, 8, 2]
using ArrayType3 = vtkm::cont::ArrayHandle<vtkm::Id>;
ArrayType3 array3;
array3.Allocate(5);
ArrayType2::WritePortalType arrayPortal3 = array3.WritePortal();
arrayPortal3.Set(0, 2);
arrayPortal3.Set(1, 7);
arrayPortal3.Set(2, 1);
arrayPortal3.Set(3, 8);
arrayPortal3.Set(4, 2);
// Create an array with [0, 0, 0, 0]
using ArrayType4 = vtkm::cont::ArrayHandleConstant<vtkm::Id>;
ArrayType4 array4(0, 5);
// Use ArrayhandleCompositeVector to create the array
// [(0,3,2,0), (1,1,7,0), (2,4,1,0), (3,1,8,0), (4,5,2,0)].
using CompositeArrayType = vtkm::cont::
ArrayHandleCompositeVector<ArrayType1, ArrayType2, ArrayType3, ArrayType4>;
CompositeArrayType compositeArray(array1, array2, array3, array4);
////
//// END-EXAMPLE ArrayHandleCompositeVectorBasic
////
CheckArray(compositeArray);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleCompositeVector
////
vtkm::cont::make_ArrayHandleCompositeVector(array1, array2, array3, array4)
////
//// END-EXAMPLE MakeArrayHandleCompositeVector
////
);
}
void Test()
{
ArrayHandleCompositeVectorBasic();
}
} // anonymous namespace
int GuideExampleArrayHandleCompositeVector(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,70 @@
//============================================================================
// 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/ArrayHandleConstant.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array,
vtkm::Id expectedLength,
typename ArrayHandleType::ValueType expectedValue)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == expectedLength, "Array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == expectedLength,
"Portal has wrong size.");
for (vtkm::Id index = 0; index < expectedLength; index++)
{
VTKM_TEST_ASSERT(test_equal(portal.Get(index), expectedValue),
"Array has wrong value.");
}
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleConstant
////
// Create an array of 50 entries, all containing the number 3. This could be
// used, for example, to represent the sizes of all the polygons in a set
// where we know all the polygons are triangles.
vtkm::cont::ArrayHandleConstant<vtkm::Id> constantArray(3, 50);
////
//// END-EXAMPLE ArrayHandleConstant
////
CheckArray(constantArray, 50, 3);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleConstant
////
// Create an array of 50 entries, all containing the number 3.
vtkm::cont::make_ArrayHandleConstant(3, 50)
////
//// END-EXAMPLE MakeArrayHandleConstant
////
,
50,
3);
}
} // anonymous namespace
int GuideExampleArrayHandleConstant(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,137 @@
//============================================================================
// 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/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
void UniformPointCoordinates()
{
std::cout << "Trying uniform point coordinates." << std::endl;
////
//// BEGIN-EXAMPLE ArrayHandleUniformPointCoordinates
////
// Create a set of point coordinates for a uniform grid in the space between
// -5 and 5 in the x direction and -3 and 3 in the y and z directions. The
// uniform sampling is spaced in 0.08 unit increments in the x direction (for
// 126 samples), 0.08 unit increments in the y direction (for 76 samples) and
// 0.24 unit increments in the z direction (for 26 samples). That makes
// 248,976 values in the array total.
vtkm::cont::ArrayHandleUniformPointCoordinates uniformCoordinates(
vtkm::Id3(126, 76, 26),
vtkm::Vec3f{ -5.0f, -3.0f, -3.0f },
vtkm::Vec3f{ 0.08f, 0.08f, 0.24f });
////
//// END-EXAMPLE ArrayHandleUniformPointCoordinates
////
VTKM_TEST_ASSERT(uniformCoordinates.GetNumberOfValues() == 248976,
"Wrong number of values in uniform coordinates.");
VTKM_TEST_ASSERT(
test_equal(uniformCoordinates.ReadPortal().Get(0), vtkm::Vec3f{ -5.0, -3.0, -3.0 }),
"Bad first point coordinate.");
VTKM_TEST_ASSERT(test_equal(uniformCoordinates.ReadPortal().Get(248975),
vtkm::Vec3f{ 5.0, 3.0, 3.0 }),
"Bad last point coordinate.");
}
template<typename ArrayHandleType>
void CheckRectilinearPointCoordinates(ArrayHandleType rectilinearCoordinates)
{
VTKM_TEST_ASSERT(rectilinearCoordinates.GetNumberOfValues() == 12,
"Wrong number of values.");
VTKM_TEST_ASSERT(test_equal(rectilinearCoordinates.ReadPortal().Get(0),
vtkm::Vec3f{ 0.0f, 0.0f, 0.0f }),
"Bad value at 0.");
VTKM_TEST_ASSERT(test_equal(rectilinearCoordinates.ReadPortal().Get(4),
vtkm::Vec3f{ 1.1f, 2.0f, 0.0f }),
"Bad value at 4.");
VTKM_TEST_ASSERT(test_equal(rectilinearCoordinates.ReadPortal().Get(11),
vtkm::Vec3f{ 5.0f, 2.0f, 0.5f }),
"Bad value at 11.");
}
void RectilinearPointCoordinates()
{
std::cout << "Trying rectilinear point coordinates." << std::endl;
////
//// BEGIN-EXAMPLE ArrayHandleCartesianProduct
////
using AxisArrayType = vtkm::cont::ArrayHandle<vtkm::Float32>;
using AxisPortalType = AxisArrayType::WritePortalType;
// Create array for x axis coordinates with values [0.0, 1.1, 5.0]
AxisArrayType xAxisArray;
xAxisArray.Allocate(3);
AxisPortalType xAxisPortal = xAxisArray.WritePortal();
xAxisPortal.Set(0, 0.0f);
xAxisPortal.Set(1, 1.1f);
xAxisPortal.Set(2, 5.0f);
// Create array for y axis coordinates with values [0.0, 2.0]
AxisArrayType yAxisArray;
yAxisArray.Allocate(2);
AxisPortalType yAxisPortal = yAxisArray.WritePortal();
yAxisPortal.Set(0, 0.0f);
yAxisPortal.Set(1, 2.0f);
// Create array for z axis coordinates with values [0.0, 0.5]
AxisArrayType zAxisArray;
zAxisArray.Allocate(2);
AxisPortalType zAxisPortal = zAxisArray.WritePortal();
zAxisPortal.Set(0, 0.0f);
zAxisPortal.Set(1, 0.5f);
// Create point coordinates for a "rectilinear grid" with axis-aligned points
// with variable spacing by taking the Cartesian product of the three
// previously defined arrays. This generates the following 3x2x2 = 12 values:
//
// [0.0, 0.0, 0.0], [1.1, 0.0, 0.0], [5.0, 0.0, 0.0],
// [0.0, 2.0, 0.0], [1.1, 2.0, 0.0], [5.0, 2.0, 0.0],
// [0.0, 0.0, 0.5], [1.1, 0.0, 0.5], [5.0, 0.0, 0.5],
// [0.0, 2.0, 0.5], [1.1, 2.0, 0.5], [5.0, 2.0, 0.5]
vtkm::cont::ArrayHandleCartesianProduct<AxisArrayType, AxisArrayType, AxisArrayType>
rectilinearCoordinates(xAxisArray, yAxisArray, zAxisArray);
////
//// END-EXAMPLE ArrayHandleCartesianProduct
////
CheckRectilinearPointCoordinates(rectilinearCoordinates);
CheckRectilinearPointCoordinates(
////
//// BEGIN-EXAMPLE MakeArrayHandleCartesianProduct
////
vtkm::cont::make_ArrayHandleCartesianProduct(xAxisArray, yAxisArray, zAxisArray)
////
//// END-EXAMPLE MakeArrayHandleCartesianProduct
////
);
}
void Test()
{
UniformPointCoordinates();
RectilinearPointCoordinates();
}
} // anonymous namespace
int GuideExampleArrayHandleCoordinateSystems(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,106 @@
//============================================================================
// 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/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array,
typename ArrayHandleType::ValueType startValue,
typename ArrayHandleType::ValueType stepValue,
vtkm::Id expectedLength)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == expectedLength, "Array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == expectedLength,
"Portal has wrong size.");
typename ArrayHandleType::ValueType expectedValue = startValue;
for (vtkm::Id index = 0; index < expectedLength; index++)
{
VTKM_TEST_ASSERT(test_equal(portal.Get(index), expectedValue),
"Array has wrong value.");
expectedValue = expectedValue + stepValue;
}
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleIndex
////
// Create an array containing [0, 1, 2, 3, ..., 49].
vtkm::cont::ArrayHandleIndex indexArray(50);
////
//// END-EXAMPLE ArrayHandleIndex
////
CheckArray(indexArray, 0, 1, 50);
////
//// BEGIN-EXAMPLE ArrayHandleCountingBasic
////
// Create an array containing [-1.0, -0.9, -0.8, ..., 0.9, 1.0]
vtkm::cont::ArrayHandleCounting<vtkm::Float32> sampleArray(-1.0f, 0.1f, 21);
////
//// END-EXAMPLE ArrayHandleCountingBasic
////
CheckArray(sampleArray, -1.0f, 0.1f, 21);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleCountingBasic
////
// Create an array containing [-1.0, -0.9, -0.8, ..., 0.9, 1.0]
vtkm::cont::make_ArrayHandleCounting(-1.0f, 0.1f, 21)
////
//// END-EXAMPLE MakeArrayHandleCountingBasic
////
,
-1.0f,
0.1f,
21);
////
//// BEGIN-EXAMPLE ArrayHandleCountingBackward
////
// Create an array containing [49, 48, 47, 46, ..., 0].
vtkm::cont::ArrayHandleCounting<vtkm::Id> backwardIndexArray(49, -1, 50);
////
//// END-EXAMPLE ArrayHandleCountingBackward
////
CheckArray(backwardIndexArray, 49, -1, 50);
CheckArray(
////
//// BEGIN-EXAMPLE ArrayHandleCountingVec
////
// Create an array containg [(0,-3,75), (1,2,25), (3,7,-25)]
vtkm::cont::make_ArrayHandleCounting(
vtkm::make_Vec(0, -3, 75), vtkm::make_Vec(1, 5, -50), 3)
////
//// END-EXAMPLE ArrayHandleCountingVec
////
,
vtkm::make_Vec(0, -3, 75),
vtkm::make_Vec(1, 5, -50),
3);
}
} // anonymous namespace
int GuideExampleArrayHandleCounting(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,67 @@
//============================================================================
// 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/Algorithm.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleDiscard.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
////
//// BEGIN-EXAMPLE ArrayHandleDiscard
////
template<typename InputArrayType, typename OutputArrayType1, typename OutputArrayType2>
VTKM_CONT void DoFoo(InputArrayType input,
OutputArrayType1 output1,
OutputArrayType2 output2);
template<typename InputArrayType>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::FloatDefault> DoBar(InputArrayType input)
{
VTKM_IS_ARRAY_HANDLE(InputArrayType);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> keepOutput;
vtkm::cont::ArrayHandleDiscard<vtkm::FloatDefault> discardOutput;
DoFoo(input, keepOutput, discardOutput);
return keepOutput;
}
////
//// END-EXAMPLE ArrayHandleDiscard
////
template<typename InputArrayType, typename OutputArrayType1, typename OutputArrayType2>
VTKM_CONT inline void DoFoo(InputArrayType input,
OutputArrayType1 output1,
OutputArrayType2 output2)
{
vtkm::cont::Algorithm::Copy(input, output1);
vtkm::cont::Algorithm::Copy(input, output2);
}
void Test()
{
vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault> inputArray(0, 10, 10);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outputArray = DoBar(inputArray);
VTKM_TEST_ASSERT(outputArray.GetNumberOfValues() == 10, "Wrong size.");
}
} // anonymous namespace
int GuideExampleArrayHandleDiscard(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,70 @@
//============================================================================
// 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/ArrayHandleExtractComponent.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 3, "Permuted array has wrong size.");
auto portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == 3, "Permuted portal has wrong size.");
VTKM_TEST_ASSERT(test_equal(portal.Get(0), 0.2), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), 1.2), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), 2.2), "Permuted array has wrong value.");
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleExtractComponent
////
using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Vec3f_64>;
// Create array with values [ (0.0, 0.1, 0.2), (1.0, 1.1, 1.2), (2.0, 2.1, 2.2) ]
ValueArrayType valueArray;
valueArray.Allocate(3);
auto valuePortal = valueArray.WritePortal();
valuePortal.Set(0, vtkm::make_Vec(0.0, 0.1, 0.2));
valuePortal.Set(1, vtkm::make_Vec(1.0, 1.1, 1.2));
valuePortal.Set(2, vtkm::make_Vec(2.0, 2.1, 2.2));
// Use ArrayHandleExtractComponent to make an array = [1.3, 2.3, 3.3].
vtkm::cont::ArrayHandleExtractComponent<ValueArrayType> extractedComponentArray(
valueArray, 2);
////
//// END-EXAMPLE ArrayHandleExtractComponent
////
CheckArray(extractedComponentArray);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleExtractComponent
////
vtkm::cont::make_ArrayHandleExtractComponent(valueArray, 2)
////
//// END-EXAMPLE MakeArrayHandleExtractComponent
////
);
}
} // anonymous namespace
int GuideExampleArrayHandleExtractComponent(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,143 @@
//============================================================================
// 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/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleGroupVec.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ConvertNumComponentsToOffsets.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(ArrayHandleType array)
{
vtkm::cont::printSummary_ArrayHandle(array, std::cout);
std::cout << std::endl;
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
vtkm::Id expectedValue = 0;
for (vtkm::Id vecIndex = 0; vecIndex < portal.GetNumberOfValues(); ++vecIndex)
{
for (vtkm::IdComponent componentIndex = 0;
componentIndex < portal.Get(vecIndex).GetNumberOfComponents();
componentIndex++)
{
VTKM_TEST_ASSERT(portal.Get(vecIndex)[componentIndex] == expectedValue,
"Got bad value.");
++expectedValue;
}
}
}
void ArrayHandleGroupVecBasic()
{
std::cout << "ArrayHandleGroupVec" << std::endl;
////
//// BEGIN-EXAMPLE ArrayHandleGroupVecBasic
////
// Create an array containing [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
using ArrayType = vtkm::cont::ArrayHandleIndex;
ArrayType sourceArray(12);
// Create an array containing [(0,1), (2,3), (4,5), (6,7), (8,9), (10,11)]
vtkm::cont::ArrayHandleGroupVec<ArrayType, 2> vec2Array(sourceArray);
// Create an array containing [(0,1,2), (3,4,5), (6,7,8), (9,10,11)]
vtkm::cont::ArrayHandleGroupVec<ArrayType, 3> vec3Array(sourceArray);
////
//// END-EXAMPLE ArrayHandleGroupVecBasic
////
CheckArray(vec2Array);
vtkm::cont::printSummary_ArrayHandle(vec3Array, std::cout);
std::cout << std::endl;
CheckArray(vec3Array);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleGroupVec
////
// Create an array containing [(0,1,2,3), (4,5,6,7), (8,9,10,11)]
vtkm::cont::make_ArrayHandleGroupVec<4>(sourceArray)
////
//// END-EXAMPLE MakeArrayHandleGroupVec
////
);
}
void ArrayHandleGroupVecVariable()
{
std::cout << "ArrayHandleGroupVecVariable" << std::endl;
////
//// BEGIN-EXAMPLE ArrayHandleGroupVecVariable
////
// Create an array of counts containing [4, 2, 3, 3]
vtkm::cont::ArrayHandle<vtkm::IdComponent> countArray =
vtkm::cont::make_ArrayHandle<vtkm::IdComponent>({ 4, 2, 3, 3 });
// Convert the count array to an offset array [0, 4, 6, 9, 12]
// Returns the number of total components: 12
vtkm::Id sourceArraySize;
using OffsetArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
OffsetArrayType offsetArray =
vtkm::cont::ConvertNumComponentsToOffsets(countArray, sourceArraySize);
//// PAUSE-EXAMPLE
vtkm::cont::printSummary_ArrayHandle(offsetArray, std::cout);
std::cout << std::endl;
VTKM_TEST_ASSERT(sourceArraySize == 12, "Bad source array size");
VTKM_TEST_ASSERT(offsetArray.GetNumberOfValues() == 5);
VTKM_TEST_ASSERT(offsetArray.ReadPortal().Get(0) == 0, "Unexpected offset value");
VTKM_TEST_ASSERT(offsetArray.ReadPortal().Get(1) == 4, "Unexpected offset value");
VTKM_TEST_ASSERT(offsetArray.ReadPortal().Get(2) == 6, "Unexpected offset value");
VTKM_TEST_ASSERT(offsetArray.ReadPortal().Get(3) == 9, "Unexpected offset value");
VTKM_TEST_ASSERT(offsetArray.ReadPortal().Get(4) == 12, "Unexpected offset value");
//// RESUME-EXAMPLE
// Create an array containing [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
using SourceArrayType = vtkm::cont::ArrayHandleIndex;
SourceArrayType sourceArray(sourceArraySize);
// Create an array containing [(0,1,2,3), (4,5), (6,7,8), (9,10,11)]
vtkm::cont::ArrayHandleGroupVecVariable<SourceArrayType, OffsetArrayType>
vecVariableArray(sourceArray, offsetArray);
////
//// END-EXAMPLE ArrayHandleGroupVecVariable
////
CheckArray(vecVariableArray);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleGroupVecVariable
////
// Create an array containing [(0,1,2,3), (4,5), (6,7,8), (9,10,11)]
vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetArray)
////
//// END-EXAMPLE MakeArrayHandleGroupVecVariable
////
);
}
void Test()
{
ArrayHandleGroupVecBasic();
ArrayHandleGroupVecVariable();
}
} // anonymous namespace
int GuideExampleArrayHandleGroupVec(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,114 @@
//============================================================================
// 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/ArrayHandlePermutation.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray1(const ArrayHandleType array)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 3, "Permuted array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == 3, "Permuted portal has wrong size.");
VTKM_TEST_ASSERT(test_equal(portal.Get(0), 0.3), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), 0.0), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), 0.1), "Permuted array has wrong value.");
}
template<typename ArrayHandleType>
void CheckArray2(const ArrayHandleType array)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 5, "Permuted array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == 5, "Permuted portal has wrong size.");
VTKM_TEST_ASSERT(test_equal(portal.Get(0), 0.1), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), 0.2), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), 0.2), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(3), 0.3), "Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(4), 0.0), "Permuted array has wrong value.");
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandlePermutation
////
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
using IdPortalType = IdArrayType::WritePortalType;
using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Float64>;
using ValuePortalType = ValueArrayType::WritePortalType;
// Create array with values [0.0, 0.1, 0.2, 0.3]
ValueArrayType valueArray;
valueArray.Allocate(4);
ValuePortalType valuePortal = valueArray.WritePortal();
valuePortal.Set(0, 0.0);
valuePortal.Set(1, 0.1);
valuePortal.Set(2, 0.2);
valuePortal.Set(3, 0.3);
// Use ArrayHandlePermutation to make an array = [0.3, 0.0, 0.1].
IdArrayType idArray1;
idArray1.Allocate(3);
IdPortalType idPortal1 = idArray1.WritePortal();
idPortal1.Set(0, 3);
idPortal1.Set(1, 0);
idPortal1.Set(2, 1);
vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> permutedArray1(
idArray1, valueArray);
//// PAUSE-EXAMPLE
CheckArray1(permutedArray1);
//// RESUME-EXAMPLE
// Use ArrayHandlePermutation to make an array = [0.1, 0.2, 0.2, 0.3, 0.0]
IdArrayType idArray2;
idArray2.Allocate(5);
IdPortalType idPortal2 = idArray2.WritePortal();
idPortal2.Set(0, 1);
idPortal2.Set(1, 2);
idPortal2.Set(2, 2);
idPortal2.Set(3, 3);
idPortal2.Set(4, 0);
vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> permutedArray2(
idArray2, valueArray);
//// PAUSE-EXAMPLE
CheckArray2(permutedArray2);
//// RESUME-EXAMPLE
////
//// END-EXAMPLE ArrayHandlePermutation
////
IdArrayType idArray = idArray2;
CheckArray2(
////
//// BEGIN-EXAMPLE MakeArrayHandlePermutation
////
vtkm::cont::make_ArrayHandlePermutation(idArray, valueArray)
////
//// END-EXAMPLE MakeArrayHandlePermutation
////
);
}
} // anonymous namespace
int GuideExampleArrayHandlePermutation(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,110 @@
//============================================================================
// 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/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleRandomStandardNormal.h>
#include <vtkm/cont/ArrayHandleRandomUniformBits.h>
#include <vtkm/cont/ArrayHandleRandomUniformReal.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleRandomUniformBits
////
// Create an array containing a sequence of random bits seeded
// by std::random_device.
vtkm::cont::ArrayHandleRandomUniformBits randomArray(50);
// Create an array containing a sequence of random bits with
// a user supplied seed.
vtkm::cont::ArrayHandleRandomUniformBits randomArraySeeded(50, { 123 });
////
//// END-EXAMPLE ArrayHandleRandomUniformBits
////
////
//// BEGIN-EXAMPLE ArrayHandleRandomUniformBitsFunctional
////
// ArrayHandleRandomUniformBits is functional, it returns
// the same value for the same entry is accessed.
auto r0 = randomArray.ReadPortal().Get(5);
auto r1 = randomArray.ReadPortal().Get(5);
assert(r0 == r1);
////
//// END-EXAMPLE ArrayHandleRandomUniformBitsFunctional
////
// In case assert is an empty expression.
VTKM_TEST_ASSERT(r0 == r1);
////
//// BEGIN-EXAMPLE ArrayHandleRandomUniformBitsIteration
////
// Create a new insance of ArrayHandleRandomUniformBits
// for each set of random bits.
vtkm::cont::ArrayHandleRandomUniformBits randomArray0(50, { 0 });
vtkm::cont::ArrayHandleRandomUniformBits randomArray1(50, { 1 });
assert(randomArray0.ReadPortal().Get(5) != randomArray1.ReadPortal().Get(5));
////
//// END-EXAMPLE ArrayHandleRandomUniformBitsIteration
////
// In case assert is an empty expression.
VTKM_TEST_ASSERT(randomArray0.ReadPortal().Get(5) != randomArray1.ReadPortal().Get(5));
{
////
//// BEGIN-EXAMPLE ArrayHandleRandomUniformReal
////
constexpr vtkm::Id NumPoints = 50;
auto randomPointsInBox = vtkm::cont::make_ArrayHandleCompositeVector(
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints),
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints),
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints));
////
//// END-EXAMPLE ArrayHandleRandomUniformReal
////
VTKM_TEST_ASSERT(randomPointsInBox.GetNumberOfValues() == NumPoints);
auto portal = randomPointsInBox.ReadPortal();
for (vtkm::Id idx = 0; idx < NumPoints; ++idx)
{
vtkm::Vec3f value = portal.Get(idx);
VTKM_TEST_ASSERT((value[0] >= 0) && (value[0] <= 1));
VTKM_TEST_ASSERT((value[1] >= 0) && (value[1] <= 1));
VTKM_TEST_ASSERT((value[2] >= 0) && (value[2] <= 1));
}
}
{
////
//// BEGIN-EXAMPLE ArrayHandleRandomStandardNormal
////
constexpr vtkm::Id NumPoints = 50;
auto randomPointsInGaussian = vtkm::cont::make_ArrayHandleCompositeVector(
vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints),
vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints),
vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints));
////
//// END-EXAMPLE ArrayHandleRandomStandardNormal
////
VTKM_TEST_ASSERT(randomPointsInGaussian.GetNumberOfValues() == NumPoints);
}
}
} // anonymous namespace
int GuideExampleArrayHandleRandom(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,75 @@
//============================================================================
// 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/ArrayHandleSwizzle.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 3, "Permuted array has wrong size.");
auto portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == 3, "Permuted portal has wrong size.");
VTKM_TEST_ASSERT(test_equal(portal.Get(0), vtkm::Vec3f_64(0.2, 0.0, 0.3)),
"Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), vtkm::Vec3f_64(1.2, 1.0, 1.3)),
"Permuted array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), vtkm::Vec3f_64(2.2, 2.0, 2.3)),
"Permuted array has wrong value.");
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleSwizzle
////
using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Vec4f_64>;
// Create array with values
// [ (0.0, 0.1, 0.2, 0.3), (1.0, 1.1, 1.2, 1.3), (2.0, 2.1, 2.2, 2.3) ]
ValueArrayType valueArray;
valueArray.Allocate(3);
auto valuePortal = valueArray.WritePortal();
valuePortal.Set(0, vtkm::make_Vec(0.0, 0.1, 0.2, 0.3));
valuePortal.Set(1, vtkm::make_Vec(1.0, 1.1, 1.2, 1.3));
valuePortal.Set(2, vtkm::make_Vec(2.0, 2.1, 2.2, 2.3));
// Use ArrayHandleSwizzle to make an array of Vec-3 with x,y,z,w swizzled to z,x,w
// [ (0.2, 0.0, 0.3), (1.2, 1.0, 1.3), (2.2, 2.0, 2.3) ]
vtkm::cont::ArrayHandleSwizzle<ValueArrayType, 3> swizzledArray(
valueArray, vtkm::IdComponent3(2, 0, 3));
////
//// END-EXAMPLE ArrayHandleSwizzle
////
CheckArray(swizzledArray);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleSwizzle
////
vtkm::cont::make_ArrayHandleSwizzle(valueArray, 2, 0, 3)
////
//// END-EXAMPLE MakeArrayHandleSwizzle
////
);
}
} // anonymous namespace
int GuideExampleArrayHandleSwizzle(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,76 @@
//============================================================================
// 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/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array,
typename ArrayHandleType::ValueType firstValue,
vtkm::Id expectedLength)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == expectedLength, "Array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == expectedLength,
"Portal has wrong size.");
typename ArrayHandleType::ValueType expectedValue = firstValue;
for (vtkm::Id index = 0; index < expectedLength; index++)
{
VTKM_TEST_ASSERT(test_equal(portal.Get(index), expectedValue),
"Array has wrong value.");
expectedValue++;
}
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleView
////
vtkm::cont::ArrayHandle<vtkm::Id> sourceArray;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(10), sourceArray);
// sourceArray has [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
vtkm::cont::ArrayHandleView<vtkm::cont::ArrayHandle<vtkm::Id>> viewArray(
sourceArray, 3, 5);
// viewArray has [3, 4, 5, 6, 7]
////
//// END-EXAMPLE ArrayHandleView
////
CheckArray(viewArray, 3, 5);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleView
////
vtkm::cont::make_ArrayHandleView(sourceArray, 3, 5)
////
//// END-EXAMPLE MakeArrayHandleView
////
,
3,
5);
}
} // anonymous namespace
int GuideExampleArrayHandleView(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -0,0 +1,88 @@
//============================================================================
// 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/ArrayHandleZip.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType array)
{
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 3, "Permuted array has wrong size.");
typename ArrayHandleType::ReadPortalType portal = array.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == 3, "Permuted portal has wrong size.");
using PairType = vtkm::Pair<vtkm::Id, vtkm::Float64>;
VTKM_TEST_ASSERT(test_equal(portal.Get(0), PairType(3, 0.0)),
"Zipped array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(1), PairType(0, 0.1)),
"Zipped array has wrong value.");
VTKM_TEST_ASSERT(test_equal(portal.Get(2), PairType(1, 0.2)),
"Zipped array has wrong value.");
}
void Test()
{
////
//// BEGIN-EXAMPLE ArrayHandleZip
////
using ArrayType1 = vtkm::cont::ArrayHandle<vtkm::Id>;
using PortalType1 = ArrayType1::WritePortalType;
using ArrayType2 = vtkm::cont::ArrayHandle<vtkm::Float64>;
using PortalType2 = ArrayType2::WritePortalType;
// Create an array of vtkm::Id with values [3, 0, 1]
ArrayType1 array1;
array1.Allocate(3);
PortalType1 portal1 = array1.WritePortal();
portal1.Set(0, 3);
portal1.Set(1, 0);
portal1.Set(2, 1);
// Create a second array of vtkm::Float32 with values [0.0, 0.1, 0.2]
ArrayType2 array2;
array2.Allocate(3);
PortalType2 portal2 = array2.WritePortal();
portal2.Set(0, 0.0);
portal2.Set(1, 0.1);
portal2.Set(2, 0.2);
// Zip the two arrays together to create an array of
// vtkm::Pair<vtkm::Id, vtkm::Float64> with values [(3,0.0), (0,0.1), (1,0.2)]
vtkm::cont::ArrayHandleZip<ArrayType1, ArrayType2> zipArray(array1, array2);
////
//// END-EXAMPLE ArrayHandleZip
////
CheckArray(zipArray);
CheckArray(
////
//// BEGIN-EXAMPLE MakeArrayHandleZip
////
vtkm::cont::make_ArrayHandleZip(array1, array2)
////
//// END-EXAMPLE MakeArrayHandleZip
////
);
}
} // anonymous namespace
int GuideExampleArrayHandleZip(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}

@ -345,7 +345,7 @@ void TryPrintArrayContents()
////
//// BEGIN-EXAMPLE CastAndCallWithFloatFallback
////
uncertainArray.CastAndCall(PrintArrayContentsFunctor{});
uncertainArray.CastAndCallWithFloatFallback(PrintArrayContentsFunctor{});
////
//// END-EXAMPLE CastAndCallWithFloatFallback
////

@ -88,7 +88,7 @@ That calls a lambda function that invokes a worklet to create the output field.
.. didyouknow::
The filter implemented in :numref:`ex:FilterFieldImpl` is limited to only find the magnitude of :class:`vtkm::Vec`'s with 3 components.
It may be the case you wish to implement a filter that operates on :class:`vtkm::Vec`'s of multiple sizes (or perhaps even any size).
Chapter \ref{chap:UnknownArrayHandle} discusses how you can use the :class:`vtkm::cont::UnknownArrayHandle` contained in the :class:`vtkm::cont::Field` to more expressively decide what types to check for.
:chapref:`unknown-array-handle:Unknown Array Handles` discusses how you can use the :class:`vtkm::cont::UnknownArrayHandle` contained in the :class:`vtkm::cont::Field` to more expressively decide what types to check for.
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallVariableVecField(const vtkm::cont::UnknownArrayHandle&, Functor&&, Args&&...) const
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallVariableVecField(const vtkm::cont::Field&, Functor&&, Args&&...) const

@ -0,0 +1,634 @@
==============================
Fancy Array Handles
==============================
.. todo:: Document :class:`vtkm::cont::ArrayHandleMultiplexer`.
.. index::
double: array handle; fancy
One of the features of using :class:`vtkm::cont::ArrayHandle` is that it hides the implementation and layout of the array behind a generic interface.
This gives us the opportunity to replace a simple C array with some custom definition of the data and the code using the :class:`vtkm::cont::ArrayHandle` is none the wiser.
This gives us the opportunity to implement *fancy* arrays that do more than simply look up a value in an array.
For example, arrays can be augmented on the fly by mutating their indices or values.
Or values could be computed directly from the index so that no storage is required for the array at all.
|VTKm| provides many of the fancy arrays, which we explore in this section.
.. didyouknow::
One of the advantages of |VTKm|'s implementation of fancy arrays is that they can define whole arrays without actually storing and values.
For example, :class:`vtkm::cont::ArrayHandleConstant`, :class:`vtkm::cont::ArrayHandleIndex`, and :class:`vtkm::cont::ArrayHandleCounting` do not store data in any array in memory.
Rather, they construct the value for an index at runtime.
Likewise, arrays like :class:`vtkm::cont::ArrayHandlePermutation` construct new arrays from the values of other arrays without having to create a copy of the data.
.. didyouknow::
This chapter documents several array handle types that modify other array handles.
:chapref:`memory-layout:Memory Layout of Array Handles` has several similar examples of modifying basic arrays to represent data in different layouts.
The difference is that the fancy array handles in this chapter decorate other array handles of any type whereas those in :numref:`Chapter {number} <memory-layout:Memory Layout of Array Handles>` only decorate basic array handles.
If you do not find the fancy array handle you are looking for here, you might try that chapter.
------------------------------
Constant Arrays
------------------------------
.. index::
single: array handle; constant
single: constant array handle
A constant array is a fancy array handle that has the same value in all of its entries.
The constant array provides this array without actually using any memory.
Specifying a constant array in |VTKm| is straightforward.
|VTKm| has a class named :class:`vtkm::cont::ArrayHandleConstant`.
:class:`vtkm::cont::ArrayHandleConstant` is a templated class with a single template argument that is the type of value for each element in the array.
The constructor for :class:`vtkm::cont::ArrayHandleConstant` takes the value to provide by the array and the number of values the array should present.
The following example is a simple demonstration of the constant array handle.
.. doxygenclass:: vtkm::cont::ArrayHandleConstant
:members:
.. load-example:: ArrayHandleConstant
:file: GuideExampleArrayHandleConstant.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleConstant`.
The :file:`vtkm/cont/ArrayHandleConstant.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleConstant` that takes a value and a size for the array.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleConstant
.. load-example:: MakeArrayHandleConstant
:file: GuideExampleArrayHandleConstant.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleConstant`.
------------------------------
Viewing a Subset of an Array
------------------------------
.. index::
single: array handle; view
single: view array handle
An array handle view is a fancy array handle that returns a subset of an already existing array handle.
The array handle view uses the same memory as the existing array handle the view was created from.
This means that changes to the data in the array handle view will also change the data in the original array handle.
.. doxygenclass:: vtkm::cont::ArrayHandleView
:members:
To use the :class:`vtkm::cont::ArrayHandleView` you must supply an :class:`vtkm::cont::ArrayHandle` to the :class:`vtkm::cont::ArrayHandleView` class constructor.
:class:`vtkm::cont::ArrayHandleView` is a templated class with a single template argument that is the :class:`vtkm::cont::ArrayHandle` type of the array that the view is being created from.
The constructor for :class:`vtkm::cont::ArrayHandleView` takes a target array, starting index, and length.
The following example shows a simple usage of the array handle view.
.. load-example:: ArrayHandleView
:file: GuideExampleArrayHandleView.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleView`.
The :file:`vtkm/cont/ArrayHandleView.h` header contains a templated convenience function :func:`vtkm::cont::make_ArrayHandleView` that takes a target array, index, and length.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleView
.. load-example:: MakeArrayHandleView
:file: GuideExampleArrayHandleView.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleView`.
------------------------------
Counting Arrays
------------------------------
.. index::
single: array handle; counting
single: counting array handle
single: array handle; index
single: index array handle
A counting array is a fancy array handle that provides a sequence of numbers.
These fancy arrays can represent the data without actually using any memory.
|VTKm| provides two versions of a counting array.
The first version is an index array that provides a specialized but common form of a counting array called an index array.
An index array has values of type :type:`vtkm::Id` that start at 0 and count up by 1 (i.e., :math:`0, 1, 2, 3,\ldots`).
The index array mirrors the array's index.
.. doxygenclass:: vtkm::cont::ArrayHandleIndex
:members:
Specifying an index array in |VTKm| is done with a class named :class:`vtkm::cont::ArrayHandleIndex`.
The constructor for :class:`vtkm::cont::ArrayHandleIndex` takes the size of the array to create.
The following example is a simple demonstration of the index array handle.
.. load-example:: ArrayHandleIndex
:file: GuideExampleArrayHandleCounting.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleIndex`.
A :func:`vtkm::cont::make_ArrayHandleIndex` convenience function is also available.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleIndex
The :class:`vtkm::cont::ArrayHandleCounting` class provides a more general form of counting.
:class:`vtkm::cont::ArrayHandleCounting` is a templated class with a single template argument that is the type of value for each element in the array.
The constructor for :class:`vtkm::cont::ArrayHandleCounting` takes three arguments: the start value (used at index 0), the step from one value to the next, and the length of the array.
The following example is a simple demonstration of the counting array handle.
.. doxygenclass:: vtkm::cont::ArrayHandleCounting
:members:
.. load-example:: ArrayHandleCountingBasic
:file: GuideExampleArrayHandleCounting.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleCounting`.
.. didyouknow::
In addition to being simpler to declare, :class:`vtkm::cont::ArrayHandleIndex` is slightly faster than :class:`vtkm::cont::ArrayHandleCounting`.
Thus, when applicable, you should prefer using :class:`vtkm::cont::ArrayHandleIndex`.
The :file:`vtkm/cont/ArrayHandleCounting.h` header also contains the templated convenience function :file:`vtkm::cont::make_ArrayHandleCounting` that also takes the start value, step, and length as arguments.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleCounting
.. load-example:: MakeArrayHandleCountingBasic
:file: GuideExampleArrayHandleCounting.cxx
:caption: Using :file:`vtkm::cont::make_ArrayHandleCounting`.
There are no fundamental limits on how :class:`vtkm::cont::ArrayHandleCounting` counts.
For example, it is possible to count backwards.
.. load-example:: ArrayHandleCountingBackward
:file: GuideExampleArrayHandleCounting.cxx
:caption: Counting backwards with :class:`vtkm::cont::ArrayHandleCounting`.
It is also possible to use :class:`vtkm::cont::ArrayHandleCounting` to make sequences of :class:`vtkm::Vec` values with piece-wise counting in each of the components.
.. load-example:: ArrayHandleCountingVec
:file: GuideExampleArrayHandleCounting.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleCounting` with :class:`vtkm::Vec` objects.
------------------------------
Cast Arrays
------------------------------
.. index::
single: array handle; cast
single: cast array handle
A cast array is a fancy array that changes the type of the elements in an array.
The cast array provides this re-typed array without actually copying or generating any data.
Instead, casts are performed as the array is accessed.
|VTKm| has a class named :class:`vtkm::cont::ArrayHandleCast` to perform this implicit casting.
:class:`vtkm::cont::ArrayHandleCast` is a templated class with two template arguments.
The first argument is the type to cast values to.
The second argument is the type of the original :class:`vtkm::cont::ArrayHandle`.
The constructor to :class:`vtkm::cont::ArrayHandleCast` takes the :class:`vtkm::cont::ArrayHandle` to modify by casting.
.. doxygenclass:: vtkm::cont::ArrayHandleCast
:members:
.. load-example:: ArrayHandleCast
:file: GuideExampleArrayHandleCast.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleCast`.
The :file:`vtkm/cont/ArrayHandleCast.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleCast` that constructs the cast array.
The first argument is the original :class:`vtkm::cont::ArrayHandle` original array to cast.
The optional second argument is of the type to cast to (or you can optionally specify the cast-to type as a template argument.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleCast
.. load-example:: MakeArrayHandleCast
:file: GuideExampleArrayHandleCast.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleCast`.
------------------------------
Discard Arrays
------------------------------
.. index::
single: array handle; discard
single discard array handle
It is sometimes the case where you will want to run an operation in |VTKm| that fills values in two (or more) arrays, but you only want the values that are stored in one of the arrays.
It is possible to allocate space for both arrays and then throw away the values that you do not want, but that is a waste of memory.
It is also possible to rewrite the functionality to output only what you want, but that is a poor use of developer time.
To solve this problem easily, |VTKm| provides :class:`vtkm::cont::ArrayHandleDiscard`.
This array behaves similar to a regular :class:`vtkm::cont::ArrayHandle` in that it can be "allocated" and has size, but any values that are written to it are immediately discarded.
:class:`vtkm::cont::ArrayHandleDiscard` takes up no memory.
.. doxygenclass:: vtkm::cont::ArrayHandleDiscard
:members:
.. load-example:: ArrayHandleDiscard
:file: GuideExampleArrayHandleDiscard.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleDiscard`.}
------------------------------
Permuted Arrays
------------------------------
.. index::
single: array handle; permutation
single: permutation array handle
A permutation array is a fancy array handle that reorders the elements in an array.
Elements in the array can be skipped over or replicated.
The permutation array provides this reordered array without actually coping any data.
Instead, indices are adjusted as the array is accessed.
Specifying a permutation array in |VTKm| is straightforward.
|VTKm| has a class named :class:`vtkm::cont::ArrayHandlePermutation` that takes two arrays: an array of values and an array of indices that maps an index in the permutation to an index of the original values.
The index array is specified first.
The following example is a simple demonstration of the permutation array handle.
.. doxygenclass:: vtkm::cont::ArrayHandlePermutation
:members:
.. load-example:: ArrayHandlePermutation
:file: GuideExampleArrayHandlePermutation.cxx
:caption: Using :class:`vtkm::cont::ArrayHandlePermutation`.
The :file:`vtkm/cont/ArrayHandlePermutation.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandlePermutation` that takes instances of the index and value array handles and returns a permutation array.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandlePermutation
.. load-example:: MakeArrayHandlePermutation
:file: GuideExampleArrayHandlePermutation.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandlePermutation`.
.. commonerrors::
When using an :class:`vtkm::cont::ArrayHandlePermutation`, take care that all the provided indices in the index array point to valid locations in the values array.
Bad indices can cause reading from or writing to invalid memory locations, which can be difficult to debug.
Also, be wary about having duplicate indices, which means that multiple array entries point to the same memory location.
This will work fine when using the array as input, but will cause a dangerous race condition if used as an output.
.. didyouknow::
You can write to a :class:`vtkm::cont::ArrayHandlePermutation` by, for example, using it as an output array.
Writes to the :class:`vtkm::cont::ArrayHandlePermutation` will go to the respective location in the source array.
However, :class:`vtkm::cont::ArrayHandlePermutation` cannot be resized.
------------------------------
Zipped Arrays
------------------------------
.. index::
single: array handle; zipped
single: zipped array handle
A zip array is a fancy array handle that combines two arrays of the same size to pair up the corresponding values.
Each element in the zipped array is a :class:`vtkm::Pair` containing the values of the two respective arrays.
These pairs are not stored in their own memory space.
Rather, the pairs are generated as the array is used.
Writing a pair to the zipped array writes the values in the two source arrays.
Specifying a zipped array in |VTKm| is straightforward.
|VTKm| has a class named :class:`vtkm::cont::ArrayHandleZip` that takes the two arrays providing values for the first and second entries in the pairs.
The following example is a simple demonstration of creating a zip array handle.
.. doxygenclass:: vtkm::cont::ArrayHandleZip
:members:
.. load-example:: ArrayHandleZip
:file: GuideExampleArrayHandleZip.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleZip`.
The :file:`vtkm/cont/ArrayHandleZip.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleZip` that takes instances of the two array handles and returns a zip array.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleZip
.. load-example:: MakeArrayHandleZip
:file: GuideExampleArrayHandleZip.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleZip`.
------------------------------
Coordinate System Arrays
------------------------------
Many of the data structures we use in |VTKm| are described in a 3D coordinate system.
Although, as we will see in :chapref:`dataset:Data Sets`, we can use any :class:`vtkm::cont::ArrayHandle` to store point coordinates, including a raw array of 3D vectors, there are some common patterns for point coordinates that we can use specialized arrays to better represent the data.
.. index::
double: array handle; uniform point coordinates
There are two fancy array handles that each handle a special form of coordinate system.
The first such array handle is :class:`vtkm::cont::ArrayHandleUniformPointCoordinates`, which represents a uniform sampling of space.
The constructor for :class:`vtkm::cont::ArrayHandleUniformPointCoordinates` takes three arguments.
The first argument is a :type:`vtkm::Id3` that specifies the number of samples in the :math:`x`, :math:`y`, and :math:`z` directions.
The second argument, which is optional, specifies the origin (the location of the first point at the lower left corner).
If not specified, the origin is set to :math:`[0,0,0]`.
The third argument, which is also optional, specifies the distance between samples in the :math:`x`, :math:`y`, and :math:`z` directions.
If not specified, the spacing is set to 1 in each direction.
.. doxygenclass:: vtkm::cont::ArrayHandleUniformPointCoordinates
:members:
.. load-example:: ArrayHandleUniformPointCoordinates
:file: GuideExampleArrayHandleCoordinateSystems.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleUniformPointCoordinates`.
.. index::
double: array handle; Cartesian product
double: array handle; rectilinear point coordinates
The second fancy array handle for special coordinate systems is :class:`vtkm::cont::ArrayHandleCartesianProduct`, which represents a rectilinear sampling of space where the samples are axis aligned but have variable spacing.
Sets of coordinates of this type are most efficiently represented by having a separate array for each component of the axis, and then for each :math:`[i,j,k]` index of the array take the value for each component from each array using the respective index.
This is equivalent to performing a Cartesian product on the arrays.
.. doxygenclass:: vtkm::cont::ArrayHandleCartesianProduct
:members:
:class:`vtkm::cont::ArrayHandleCartesianProduct` is a templated class.
It has three template parameters, which are the types of the arrays used for the :math:`x`, :math:`y`, and :math:`z` axes.
The constructor for :class:`vtkm::cont::ArrayHandleCartesianProduct` takes the three arrays.
.. load-example:: ArrayHandleCartesianProduct
:file: GuideExampleArrayHandleCoordinateSystems.cxx
:caption: Using a :class:`vtkm::cont::ArrayHandleCartesianProduct`.
The :file:`vtkm/cont/ArrayHandleCartesianProduct.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleCartesianProduct` that takes the three axis arrays and returns an array of the Cartesian product.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleCartesianProduct
.. load-example:: MakeArrayHandleCartesianProduct
:file: GuideExampleArrayHandleCoordinateSystems.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleCartesianProduct`.
.. didyouknow::
These specialized arrays for coordinate systems greatly reduce the code duplication in |VTKm|.
Most scientific visualization systems need separate implementations of algorithms for uniform, rectilinear, and unstructured grids.
But in |VTKm| an algorithm can be written once and then applied to all these different grid structures by using these specialized array handles and letting the compiler's templates optimize the code.
.. didyouknow::
The special array handles in this section are designed to represent point coordinates in particular, common configurations.
However, the array for a :class:`vtkm::cont::CoordinateSystem` does not have to be one of these arrays.
For example, it is common to use a :class:`vtkm::cont::ArrayHandleBasic` to represent points in general position.
------------------------------
Composite Vector Arrays
------------------------------
.. index::
double: array handle; composite vector
A composite vector array is a fancy array handle that combines two to four arrays of the same size and value type and combines their corresponding values to form a :class:`vtkm::Vec`.
A composite vector array is similar in nature to a zipped array (described in :secref:`fancy-array-handles:Zipped Arrays`) except that values are combined into :class:`vtkm::Vec`'s instead of :class:`vtkm::Pair`'s.
The composite vector array is also similar to a structure of arrays (described in :secref:`memory-layout:Structure of Arrays`) except that any type of array handles can be used for the components rather than a basic array handle.
The created :class:`vtkm::Vec`'s are not stored in their own memory space.
Rather, the :class:`vtkm::Vec`'s are generated as the array is used.
Writing :class:`vtkm::Vec`'s to the composite vector array writes values into the components of the source arrays.
A composite vector array can be created using the :class:`vtkm::cont::ArrayHandleCompositeVector` class.
This class has a variadic template argument that is a "signature" for the arrays to be combined.
The constructor for :class:`vtkm::cont::ArrayHandleCompositeVector` takes instances of the array handles to combine.
.. doxygenclass:: vtkm::cont::ArrayHandleCompositeVector
:members:
.. load-example:: ArrayHandleCompositeVectorBasic
:file: GuideExampleArrayHandleCompositeVector.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleCompositeVector`.
The :file:`vtkm/cont/ArrayHandleCompositeVector.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleCompositeVector` which takes a variable number of array handles and returns an :class:`vtkm::cont::ArrayHandleCompositeVector`.
This function can sometimes be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleCompositeVector
.. load-example:: MakeArrayHandleCompositeVector
:file: GuideExampleArrayHandleCompositeVector.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleCompositeVector`.
------------------------------
Extract Component Arrays
------------------------------
.. index::
double: array handle; extract component
Component extraction allows access to a single component of an :class:`vtkm::cont::ArrayHandle` with a :class:`vtkm::Vec` as the :member:`vtkm::cont::ArrayHandle::ValueType`.
:class:`vtkm::cont::ArrayHandleExtractComponent` allows one component of a vector array to be extracted without creating a copy of the data.
:class:`vtkm::cont::ArrayHandleExtractComponent` can also be combined with :class:`vtkm::cont::ArrayHandleCompositeVector` (described in :secref:`fancy-array-handles:Composite Vector Arrays`) to arbitrarily stitch several components from multiple arrays together.
.. doxygenclass:: vtkm::cont::ArrayHandleExtractComponent
:members:
As a simple example, consider an :class:`vtkm::cont::ArrayHandle` containing 3D coordinates for a collection of points and a filter that only operates on the points' elevations (Z, in this example).
We can easily create the elevation array on-the-fly without allocating a new array as in the following example.
.. load-example:: ArrayHandleExtractComponent
:file: GuideExampleArrayHandleExtractComponent.cxx
:caption: Extracting components of :class:`vtkm::Vec`'s in an array with :class:`vtkm::cont::ArrayHandleExtractComponent`.
The :file:`vtkm/cont/ArrayHandleExtractComponent.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleExtractComponent` that takes an :class:`vtkm::cont::ArrayHandle` of :class:`vtkm::Vec`'s and :type:`vtkm::IdComponent` which returns an appropriately typed :class:`vtkm::cont::ArrayHandleExtractComponent` containing the values for a specified component.
The index of the component to extract is provided as an argument to :func:`vtkm::cont::make_ArrayHandleExtractComponent`, which is required.
The use of :func:`vtkm::cont::make_ArrayHandleExtractComponent` can be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleExtractComponent
.. load-example:: MakeArrayHandleExtractComponent
:file: GuideExampleArrayHandleExtractComponent.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleExtractComponent`.
.. didyouknow::
An alternate way to extract a component from a :class:`vtkm::cont::ArrayHandle` is to use the :func:`vtkm::cont::ArrayExtractComponent` function.
Rather than wrap a :class:`vtkm::cont::ArrayHandleExtractComponent` around the target array, it converts the array into a :class:`vtkm::cont::ArrayHandleStride`, as described in :secref:`memory-layout:Strided Arrays`.
This can be advantageous when trying to unify the storage type of different array types, but can work poorly for some array types.
------------------------------
Swizzle Arrays
------------------------------
.. index::
double: array handle; swizzle
It is often useful to reorder or remove specific components from an :class:`vtkm::cont::ArrayHandle` with a :class:`vtkm::Vec` :member:`vtkm::cont::ArrayHandle::ValueType`.
:class:`vtkm::cont::ArrayHandleSwizzle` provides an easy way to accomplish this.
The constructor of :class:`vtkm::cont::ArrayHandleSwizzle` specifies a "component map," which defines the swizzle operation.
This map consists of the components from the input :class:`vtkm::cont::ArrayHandle`, which will be exposed in the :class:`vtkm::cont::ArrayHandleSwizzle`.
For instance, constructing ``vtkm::cont::ArrayHandleSwizzle<Some3DArrayType, 3>`` with ``vtkm::IdComponent3(0, 2, 1)`` as the second constructor argument will allow access to a 3D array, but with the Y and Z components exchanged.
This rearrangement does not create a copy, and occurs on-the-fly as data are accessed through the :class:`vtkm::cont::ArrayHandleSwizzle`'s portal.
This fancy array handle can also be used to eliminate unnecessary components from an :class:`vtkm::cont::ArrayHandle`'s data, as shown below.
.. doxygenclass:: vtkm::cont::ArrayHandleSwizzle
:members:
.. load-example:: ArrayHandleSwizzle
:file: GuideExampleArrayHandleSwizzle.cxx
:caption: Swizzling components of :class:`vtkm::Vec`'s in an array with :class:`vtkm::cont::ArrayHandleSwizzle`.
The :file:`vtkm/cont/ArrayHandleSwizzle.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleSwizzle` that takes an :class:`vtkm::cont::ArrayHandle` of :class:`vtkm::Vec`'s and returns an appropriately typed :class:`vtkm::cont::ArrayHandleSwizzle` containing swizzled vectors.
The use of :func:`vtkm::cont::make_ArrayHandleSwizzle` can be used to avoid having to declare the full array type.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSwizzle(const ArrayHandleType&, const vtkm::Vec<vtkm::IdComponent, OutSize>&)
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSwizzle(const ArrayHandleType&, vtkm::IdComponent, SwizzleIndexTypes...)
.. load-example:: MakeArrayHandleSwizzle
:file: GuideExampleArrayHandleSwizzle.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleSwizzle`.
------------------------------
Grouped Vector Arrays
------------------------------
.. index::
double: array handle; group vector
A grouped vector array is a fancy array handle that groups consecutive values of an array together to form a :class:`vtkm::Vec`.
The source array must be of a length that is divisible by the requested :class:`vtkm::Vec` size.
The created :class:`vtkm::Vec`'s are not stored in their own memory space.
Rather, the :class:`vtkm::Vec`'s are generated as the array is used.
Writing :class:`vtkm::Vec`'s to the grouped vector array writes values into the the source array.
A grouped vector array is created using the :class:`vtkm::cont::ArrayHandleGroupVec` class.
This templated class has two template arguments.
The first argument is the type of array being grouped and the second argument is an integer specifying the size of the :class:`vtkm::Vec`'s to create (the number of values to group together).
.. doxygenclass:: vtkm::cont::ArrayHandleGroupVec
:members:
.. load-example:: ArrayHandleGroupVecBasic
:file: GuideExampleArrayHandleGroupVec.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleGroupVec`.
The :file:`vtkm/cont/ArrayHandleGroupVec.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleGroupVec` that takes an instance of the array to group into :class:`vtkm::Vec`'s.
You must specify the size of the :class:`vtkm::Vec`'s as a template parameter when using :func:`vtkm::cont::make_ArrayHandleGroupVec`.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleGroupVec
.. load-example:: MakeArrayHandleGroupVec
:file: GuideExampleArrayHandleGroupVec.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleGroupVec`.
.. didyouknow::
:class:`vtkm::cont::ArrayHandleGroupVec` requires you to specify the number of components at compile time.
For a similar functionality, consider using :class:`vtkm::cont::ArrayHandleRuntimeVec`, described in :secref:`memory-layout:Runtime Vec Arrays`.
This allows the runtime selection of :class:`vtkm::Vec` sizes and can be applied to existing basic arrays, but is limited in other ways.
:class:`vtkm::cont::ArrayHandleGroupVec` is handy when you need to build an array of vectors that are all of the same length, but what about when you need an array of vectors of different lengths?
One common use case for this is if you are defining a collection of polygons of different sizes (triangles, quadrilaterals, pentagons, and so on).
We would like to define an array such that the data for each polygon were stored in its own :class:`vtkm::Vec` (or, rather, |Veclike|) object.
:class:`vtkm::cont::ArrayHandleGroupVecVariable` does just that.
:class:`vtkm::cont::ArrayHandleGroupVecVariable` takes two arrays. The first array, identified as the "source" array, is a flat representation of the values (much like the array used with :class:`vtkm::cont::ArrayHandleGroupVec`).
The second array, identified as the "offsets" array, provides for each vector the index into the source array where the start of the vector is.
The offsets array must be monotonically increasing.
The size of the offsets array is one greater than the number of vectors in the resulting array.
The first offset is always 0 and the last offset is always the size of the input source array.
The first and second template parameters to :class:`vtkm::cont::ArrayHandleGroupVecVariable` are the types for the source and offset arrays, respectively.
.. doxygenclass:: vtkm::cont::ArrayHandleGroupVecVariable
:members:
It is often the case that you will start with a group of vector lengths rather than offsets into the source array.
If this is the case, then the :func:`vtkm::cont::ConvertNumComponentsToOffsets` helper function can convert an array of vector lengths to an array of offsets.
The first argument to this function is always the array of vector lengths.
The second argument, which is optional, is a reference to a :class:`vtkm::cont::ArrayHandle` into which the offsets should be stored.
If this offset array is not specified, an :class:`vtkm::cont::ArrayHandle` will be returned from the function instead.
The third argument, which is also optional, is a reference to a :type:`vtkm::Id` into which the expected size of the source array is put.
Having the size of the source array is often helpful, as it can be used to allocate data for the source array or check the source array's size.
It is also OK to give the expected size reference but not the offset array reference.
.. doxygenfunction:: vtkm::cont::ConvertNumComponentsToOffsets(const vtkm::cont::UnknownArrayHandle&, vtkm::cont::ArrayHandle<vtkm::Id>&, vtkm::Id&, vtkm::cont::DeviceAdapterId)
.. load-example:: ArrayHandleGroupVecVariable
:file: GuideExampleArrayHandleGroupVec.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleGroupVecVariable`.
The :file:`vtkm/cont/ArrayHandleGroupVecVariable.h` header also contains the templated convenience function :func:`vtkm::cont::make_ArrayHandleGroupVecVariable` that takes an instance of the source array to group into |Veclike| objects and the offset array.
.. doxygenfunction:: vtkm::cont::make_ArrayHandleGroupVecVariable
.. load-example:: MakeArrayHandleGroupVecVariable
:file: GuideExampleArrayHandleGroupVec.cxx
:caption: Using :func:`vtkm::cont::make_ArrayHandleGroupVecVariable`.
.. didyouknow::
You can write to :class:`vtkm::cont::ArrayHandleGroupVec` and :class:`vtkm::cont::ArrayHandleGroupVecVariable` by, for example, using it as an output array.
Writes to these arrays will go to the respective location in the source array.
:class:`vtkm::cont::ArrayHandleGroupVec` can also be allocated and resized (which in turn causes the source array to be allocated).
However, :class:`vtkm::cont::ArrayHandleGroupVecVariable` cannot be resized and the source array must be pre-allocated.
You can use the source array size value returned from :func:`vtkm::cont::ConvertNumComponentsToOffsets` to allocate source arrays.
.. commonerrors::
Keep in mind that the values stored in a :class:`vtkm::cont::ArrayHandleGroupVecVariable` are not actually :class:`vtkm::Vec` objects.
Rather, they are "|Veclike|" objects, which has some subtle but important ramifications.
First, the type will not match the :class:`vtkm::Vec` template, and there is no automatic conversion to :class:`vtkm::Vec` objects.
Thus, many functions that accept :class:`vtkm::Vec` objects as parameters will not accept the |Veclike| object.
Second, the size of |Veclike| objects are not known until runtime.
See :secref:`base-types:Vector Types` and :secref:`advanced-types:Vector Traits` for more information on the difference between :class:`vtkm::Vec` and |Veclike| objects.
------------------------------
Random Arrays
------------------------------
.. index::
double: array handle; random
The basis of generating random numbers in |VTKm| is built on the :class:`vtkm::cont::ArrayHandleRandomUniformBits`.
An uniform random bits array is a fancy array handle that generates pseudo random bits as :type:`vtkm::Unit64` in its entries.
The uniform random bits array provides this array without actually using any memory.
.. doxygenclass:: vtkm::cont::ArrayHandleRandomUniformBits
:members:
The constructor for :class:`vtkm::cont::ArrayHandleRandomUniformBits` takes two arguments: the first argument is the length of the array handle, the second is a seed of type ``vtkm::Vec<Uint32, 1>``.
If the seed is not specified, the C++11 ``std::random_device`` is used as default.
.. load-example:: ArrayHandleRandomUniformBits
:file: GuideExampleArrayHandleRandom.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleRandomUniformBits`.
:class:`vtkm::cont::ArrayHandleRandomUniformBits` is functional, in the sense that once an instance of :class:`vtkm::cont::ArrayHandleRandomUniformBits` is created, its content does not change and always returns the same :type:`vtkm::UInt64` value given the same index.
.. load-example:: ArrayHandleRandomUniformBitsFunctional
:file: GuideExampleArrayHandleRandom.cxx
:caption: :class:`vtkm::cont::ArrayHandleRandomUniformBits` is functional.
To generate a new set of random bits, we need to create another instance of :class:`vtkm::cont::ArrayHandleRandomUniformBits` with a different seed, we can either let ``std::random_device`` provide a unique seed or use some unique identifier such as iteration number as the seed.
.. load-example:: ArrayHandleRandomUniformBitsIteration
:file: GuideExampleArrayHandleRandom.cxx
:caption: Independent :class:`vtkm::cont::ArrayHandleRandomUniformBits`.
The random bits provided by :class:`vtkm::cont::ArrayHandleRandomUniformBits` can be manipulated to provide random numbers with specific distributions.
|VTKm| provides some specialized classes that implement common distributions.
The :class:`vtkm::cont::ArrayHandleRandomUniformReal` class generates an array of numbers sampled from a real uniform distribution in the range :math:`[0, 1)`.
.. doxygenclass:: vtkm::cont::ArrayHandleRandomUniformReal
:members:
.. load-example:: ArrayHandleRandomUniformReal
:file: GuideExampleArrayHandleRandom.cxx
:caption: Generating a random cloud of point coordinates in the box bounded by [0, 1].
The :class:`vtkm::cont::ArrayHandleRandomStandardNormal` class generates an array of numbers sampled from a standard normal distribution.
This provides a set of points centered at 0 and with probability exponentially diminishing away from 0 in both the positive and negative directions.
.. doxygenclass:: vtkm::cont::ArrayHandleRandomStandardNormal
:members:
.. load-example:: ArrayHandleRandomStandardNormal
:file: GuideExampleArrayHandleRandom.cxx
:caption: Generating a random cloud of point coordinates in a Gaussian distribution centered at the origin.
.. didyouknow::
The distributions of the provided random array handles can manipulated by shifting and scaling the values they provide.
This will keep the general distribution shape but change the range.
This manipulation can happen in a worklet from the values returned from the arrays or they can be generated automatically by wrapping the random arrays in a :class:`vtkm::cont::ArrayHandleTransform`.
.. todo:: Add a reference to the section describing :class:`vtkm::cont::ArrayHandleTransform`.

@ -23,9 +23,9 @@ David Pugmire,
Nick Thompson,
Allison Vacanti,
Abhishek Yenpure,
and the |VTKm| community
and the |VTKm| community.
Moreland, K. (|report-year|). *The VTK-m User's Guide*, Tech report |report-number|, Oak Ridge National Laboratory.
Moreland, K. (|report-year|). *The VTK-m User's Guide*, version |release|, Tech report |report-number|, Oak Ridge National Laboratory.
.. centered:: Join the VTK-m Community at http://m.vtk.org.

@ -19,6 +19,44 @@ But it can also optionally take the ``argc`` and ``argv`` arguments to the ``mai
|VTKm| accepts arguments that, for example, configure the compute device to use or establish logging levels.
Any arguments that are handled by |VTKm| are removed from the ``argc``/``argv`` list so that your program can then respond to the remaining arguments.
Many options can also be set with environment variables.
If both the environment variable and command line argument are provided, the command line argument is used.
The following table lists the currently supported options.
.. list-table:: |VTKm| command line arguments and environment variable options.
:widths: 23 22 15 40
:header-rows: 1
* - Command Line Argument
- Environment Variable
- Default Value
- Description
* - ``--vtkm-help``
-
-
- Causes the program to print information about |VTKm| command line arguments and then exits the program.
* - ``--vtkm-log-level``
- ``VTKM_LOG_LEVEL``
- ``WARNING``
- Specifies the logging level.
Valid values are ``INFO``, ``WARNING``, ``ERROR``, ``FATAL``, and ``OFF``.
This can also be set to a numeric value for the logging level.
* - ``--vtkm-device``
- ``VTKM_DEVICE``
-
- Force |VTKm| to use the specified device.
If not specified or ``Any`` given, then any available device may be used.
* - ``--vtkm-num-threads``
- ``VTKM_NUM_THREADS``
-
- Set the number of threads to use on a multi-core device.
If not specified, the device will use the cores available in the system.
* - ``--vtkm-device-instance``
- ``VTKM_DEVICE_INSTANCE``
-
- Selects the device to use when more than one device device of a given type is available.
The device is specified with a numbered index.
:func:`vtkm::cont::Initialize` returns a :struct:`vtkm::cont::InitializeResult` structure.
This structure contains information about the supported arguments and options selected during initialization.

@ -83,8 +83,6 @@ Additionally, you can use its constructors or the :func:`vtkm::cont::make_ArrayH
Strided Arrays
--------------------
.. todo:: Should this be moved to the chapter/section on transformed arrays?
.. index::
double: array handle; stride
double: array handle; offset
@ -163,3 +161,14 @@ This is convenient for operations that want to operate on arrays with an unknown
.. load-example:: GetRuntimeVec
:file: GuideExampleArrayHandleRuntimeVec.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleRuntimeVec` to get an array regardless of the size of the contained :class:`vtkm::Vec` values.
---------------------------------------------
Recombined Vec Arrays of Strided Components
---------------------------------------------
|VTKm| contains a special array, :class:`vtkm::cont::ArrayHandleRecombineVec`, to combine component arrays represented in :class:`vtkm::cont::ArrayHandleStride` together to form `Vec` values.
:class:`vtkm::cont::ArrayHandleRecombineVec` is similar to :class:`vtkm::cont::ArrayHandleSOA` (see :secref:`memory-layout:Structure of Arrays`) except that (1) it holds stride arrays for its components instead of basic arrays and that (2) the number of components can be specified at runtime.
:class:`vtkm::cont::ArrayHandleRecombineVec` is mainly provided for the implementation of extracting arrays out of a :class:`vtkm::cont::UnknownArrayHandle` (see :secref:`unknown-array-handle:Extracting All Components`).
.. doxygenclass:: vtkm::cont::ArrayHandleRecombineVec

@ -13,3 +13,4 @@ Advanced Development
math.rst
working-with-cells.rst
memory-layout.rst
fancy-array-handles.rst

@ -9,3 +9,4 @@ Developing Algorithms
basic-array-handles.rst
simple-worklets.rst
basic-filter-impl.rst
unknown-array-handle.rst

@ -0,0 +1,457 @@
==============================
Unknown Array Handles
==============================
.. index::
single: unknown array handle
single: array handle; unknown
The :class:`vtkm::cont::ArrayHandle` class uses templating to make very efficient and type-safe access to data.
However, it is sometimes inconvenient or impossible to specify the element type and storage at run-time.
The :class:`vtkm::cont::UnknownArrayHandle` class provides a mechanism to manage arrays of data with unspecified types.
:class:`vtkm::cont::UnknownArrayHandle` holds a reference to an array.
Unlike :class:`vtkm::cont::ArrayHandle`, :class:`vtkm::cont::UnknownArrayHandle` is *not* templated.
Instead, it uses C++ run-type type information to store the array without type and cast it when appropriate.
.. doxygenclass:: vtkm::cont::UnknownArrayHandle
.. index:: unknown array handle; construct
An :class:`vtkm::cont::UnknownArrayHandle` can be established by constructing it with or assigning it to an :class:`vtkm::cont::ArrayHandle`.
The following example demonstrates how an :class:`vtkm::cont::UnknownArrayHandle` might be used to load an array whose type is not known until run-time.
.. load-example:: CreateUnknownArrayHandle
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::UnknownArrayHandle`.
It is possible to construct a :class:`vtkm::cont::UnknownArrayHandle` that does not point to any :class:`vtkm::cont::ArrayHandle`.
In this case, the :class:`vtkm::cont::UnknownArrayHandle` is considered not "valid."
Validity can be tested with the :func:`vtkm::cont::UnknownArrayHandle::IsValid` method.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsValid
Most of the following operations on :class:`vtkm::cont::UnknownArrayHandle` will fail by throwing an exception if it is not valid.
Note that it is also possible for a :class:`vtkm::cont::UnknownArrayHandle` to contain an empty :class:`vtkm::cont::ArrayHandle`.
A :class:`vtkm::cont::UnknownArrayHandle` that contains a :class:`vtkm::cont::ArrayHandle` but has no memory allocated is still considered valid.
Some basic, human-readable information can be retrieved using the :func:`vtkm::cont::UnknownArrayHandle::PrintSummary` method.
It will print the type and size of the array along with some or all of the values.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::PrintSummary
------------------------------
Allocation
------------------------------
.. index:: unknown array handle; allocation
Data pointed to by an :class:`vtkm::cont::UnknownArrayHandle` is not directly accessible.
However, it is still possible to do some type-agnostic manipulation of the array allocations.
First, it is always possible to call :func:`vtkm::cont::UnknownArrayHandle::GetNumberOfValues` to retrieve the current size of the array.
It is also possible to call :func:`vtkm::cont::UnknownArrayHandle::Allocate` to change the size of an unknown array.
:class:`vtkm::cont::UnknownArrayHandle`'s :func:`vtkm::cont::UnknownArrayHandle::Allocate` works exactly the same as the :func:`vtkm::cont::ArrayHandle::Allocate` in the basic :class:`vtkm::cont::ArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetNumberOfValues
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id, vtkm::CopyFlag, vtkm::cont::Token&) const
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id, vtkm::CopyFlag) const
.. load-example:: UnknownArrayHandleResize
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Checking the size of a :class:`vtkm::cont::ArrayHandle` and resizing it.
It is often the case where you have an :class:`vtkm::cont::UnknownArrayHandle` as the input to an operation and you want to generate an output of the same type.
To handle this case, use the :func:`vtkm::cont::UnknownArrayHandle::NewInstance` method to create a new array of the same type (without having to determine the type).
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstance
.. load-example:: NonTypeUnknownArrayHandleNewInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new instance of an unknown array handle.
That said, there are many special array handles described in :chapref:`memory-layout:Memory Layout of Array Handles` and :chapref:`fancy-array-handles:Fancy Array Handles` that either cannot be directly constructed or cannot be used as outputs.
Thus, if you do not know the storage of the array, the similar array returned by :func:`vtkm::cont::UnknownArrayHandle::NewInstance` could be infeasible for use as an output.
Thus, :class:`vtkm::cont::UnknownArrayHandle` also contains the :func:`vtkm::cont::UnknownArrayHandle::NewInstanceBasic` method to create a new array with the same value type but using the basic array storage, which can always be resized and written to.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstanceBasic
.. load-example:: UnknownArrayHandleBasicInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new basic instance of an unknown array handle.
It is sometimes the case that you need a new array of a similar type, but that type has to hold floating point values.
For example, if you had an operation that computed a discrete cosine transform on an array, the result would be very inaccurate if stored as integers.
In this case, you would actually want to store the result in an array of floating point values.
For this case, you can use the :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` to create a new basic :class:`vtkm::cont::ArrayHandle` with the component type changed to :type:`vtkm::FloatDefault`.
For example, if the :class:`vtkm::cont::UnknownArrayHandle` stores an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Id`, :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` will create an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::FloatDefault`.
If the :class:`vtkm::cont::UnknownArrayHandle` stores an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Id3`, :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` will create an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Vec3f`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic
.. load-example:: UnknownArrayHandleFloatInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new array instance with floating point values.
Finally, it may be the case where you are finished using a :class:`vtkm::cont::UnknownArrayHandle`.
If you want to free up memory on the device, which may have limited memory, you can do so with :func:`vtkm::cont::UnknownArrayHandle::ReleaseResourcesExecution`, which will free any memory on the device but preserve the data on the host.
If the data will never be used again, all memory can be freed with :func:`vtkm::cont::UnknownArrayHandle::ReleaseResources`
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ReleaseResourcesExecution
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ReleaseResources
------------------------------
Casting to Known Types
------------------------------
.. index::
single: unknown array handle; cast
single: unknown array handle; as array handle
Data pointed to by an :class:`vtkm::cont::UnknownArrayHandle` is not directly
accessible.
To access the data, you need to retrieve the data as an :class:`vtkm::cont::ArrayHandle`.
If you happen to know (or can guess) the type, you can use the :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` method to retrieve the array as a specific type.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T, S>&) const
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::AsArrayHandle() const
.. load-example:: UnknownArrayHandleAsArrayHandle1
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Retrieving an array of a known type from :class:`vtkm::cont::UnknownArrayHandle`.
:func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` actually has two forms.
The first form, shown in the previous example, has no arguments and returns the :class:`vtkm::cont::ArrayHandle`.
This form requires you to specify the type of array as a template parameter.
The alternate form has you pass a reference to a concrete :class:`vtkm::cont::ArrayHandle` as an argument as shown in the following example.
This form can imply the template parameter from the argument.
.. load-example:: UnknownArrayHandleAsArrayHandle2
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Alternate form for retrieving an array of a known type from :class:`vtkm::cont::UnknownArrayHandle`.
:func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` treats :class:`vtkm::cont::ArrayHandleCast` and :class:`vtkm::cont::ArrayHandleMultiplexer` special.
If the special :class:`vtkm::cont::ArrayHandle` can hold the actual array stored, then :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` will return successfully.
In the following example, :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` returns an array of type :type:`vtkm::Float32` as an :class:`vtkm::cont::ArrayHandleCast` that converts the values to :type:`vtkm::Float64`.
.. load-example:: UnknownArrayHandleAsCastArray
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Getting a cast array handle from an :class:`vtkm::cont::ArrayHandleCast`.
.. didyouknow::
The inverse retrieval works as well.
If you create an :class:`vtkm::cont::UnknownArrayHandle` with an :class:`vtkm::cont::ArrayHandleCast` or :class:`vtkm::cont::ArrayHandleMultiplexer`, you can get the underlying array with :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`.
These relationships also work recursively (e.g. an array placed in a cast array that is placed in a multiplexer).
.. index:: unknown array handle; query type
If the :class:`vtkm::cont::UnknownArrayHandle` cannot store its array in the type given to :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`, it will throw an exception.
Thus, you should not use :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` with types that you are not sure about.
Use the :func:`vtkm::cont::UnknownArrayHandle::CanConvert` method to determine if a given :class:`vtkm::cont::ArrayHandle` type will work with :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CanConvert
.. load-example:: UnknownArrayHandleCanConvert
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Querying whether a given :class:`vtkm::cont::ArrayHandle` can be retrieved from a :class:`vtkm::cont::UnknownArrayHandle`.
By design, :func:`vtkm::cont::UnknownArrayHandle::CanConvert` will return true for types that are not actually stored in the :class:`vtkm::cont::UnknownArrayHandle` but can be retrieved.
If you need to know specifically what type is stored in the :class:`vtkm::cont::UnknownArrayHandle`, you can use the :func:`vtkm::cont::UnknownArrayHandle::IsType` method instead.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsType
If you need to query either the value type or the storage, you can use :func:`vtkm::cont::UnknownArrayHandle::IsValueType` and :func:`vtkm::cont::UnknownArrayHandle::IsStorageType`, respectively.
:class:`vtkm::cont::UnknownArrayHandle` also provides :func:`vtkm::cont::UnknownArrayHandle::GetValueTypeName`, :func:`vtkm::cont::UnknownArrayHandle::GetStorageTypeName`, and :func:`vtkm::cont::UnknownArrayHandle::GetArrayTypeName` for debugging purposes.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsValueType
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsStorageType
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetValueTypeName
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetStorageTypeName
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetArrayTypeName
.. commonerrors::
:func:`vtkm::cont::UnknownArrayHandle::CanConvert` is almost always safer to use than :func:`vtkm::cont::UnknownArrayHandle::IsType` or its similar methods.
Even though :func:`vtkm::cont::UnknownArrayHandle::IsType` reflects the actual array type, :func:`vtkm::cont::UnknownArrayHandle::CanConvert` better describes how :class:`vtkm::cont::UnknownArrayHandle` will behave.
If you do not know the exact type of the array contained in an :class:`vtkm::cont::UnknownArrayHandle`, a brute force method to get the data out is to copy it to an array of a known type.
This can be done with the :func:`vtkm::cont::UnknownArrayHandle::DeepCopyFrom` method, which will copy the contents of a target array into an existing array of a (potentially) different type.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle&) const
.. load-example:: UnknownArrayHandleDeepCopy
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Deep copy arrays of unknown types.
It is often the case that you have good reason to believe that an array is of an expected type, but you have no way to be sure.
To simplify code, the most rational thing to do is to get the array as the expected type if that is indeed what it is, or to copy it to an array of that type otherwise.
The :func:`vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible` does just that.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle&) const
.. load-example:: UnknownArrayHandleShallowCopy
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using :func:`vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible` to get an unknown array as a particular type.
.. didyouknow::
The :class:`vtkm::cont::UnknownArrayHandle` copy methods behave similarly to the :func:`vtkm::cont::ArrayCopy` functions.
----------------------------------------
Casting to a List of Potential Types
----------------------------------------
.. index:: unknown array handle; cast
Using :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` is fine as long as the correct types are known, but often times they are not.
For this use case :class:`vtkm::cont::UnknownArrayHandle` has a method named :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` that attempts to cast the array to some set of types.
The :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` method accepts a functor to run on the appropriately cast array.
The functor must have an overloaded const parentheses operator that accepts an :class:`vtkm::cont::ArrayHandle` of the appropriate type.
You also have to specify two template parameters that specify a :class:`vtkm::List` of value types to try and a :class:`vtkm::List` of storage types to try, respectively.
The macros :c:macro:`VTKM_DEFAULT_TYPE_LIST` and :c:macro:`VTKM_DEFAULT_STORAGE_LIST` are often used when nothing more specific is known.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallForTypes
.. load-example:: UsingCastAndCallForTypes
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Operating on an :class:`vtkm::cont::UnknownArrayHandle` with :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes`.
.. didyouknow::
The first (required) argument to :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` is the functor to call with the array.
You can supply any number of optional arguments after that.
Those arguments will be passed directly to the functor.
This makes it easy to pass state to the functor.
.. didyouknow::
When an :class:`vtkm::cont::UnknownArrayHandle` is used in place of an :class:`vtkm::cont::ArrayHandle` as an argument to a worklet invocation, it will internally use :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` to attempt to call the worklet with an :class:`vtkm::cont::ArrayHandle` of the correct type.
:class:`vtkm::cont::UnknownArrayHandle` has a simple subclass named :class:`vtkm::cont::UncertainArrayHandle` for use when you can narrow the array to a finite set of types.
:class:`vtkm::cont::UncertainArrayHandle` has two template parameters that must be specified: a :class:`vtkm::List` of value types and a :class:`vtkm::List` of storage types.
.. doxygenclass:: vtkm::cont::UncertainArrayHandle
:class:`vtkm::cont::UncertainArrayHandle` has a method named :func:`vtkm::cont::UncertainArrayHandle::CastAndCall` that behaves the same as :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` except that you do not have to specify the types to try.
Instead, the types are taken from the template parameters of the :class:`vtkm::cont::UncertainArrayHandle` itself.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::CastAndCall
.. load-example:: UncertainArrayHandle
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using :class:`vtkm::cont::UncertainArrayHandle` to cast and call a functor.
.. didyouknow::
Like with :class:`vtkm::cont::UnknownArrayHandle`, if an :class:`vtkm::cont::UncertainArrayHandle` is used in a worklet invocation, it will internally use :func:`vtkm::cont::UncertainArrayHandle::CastAndCall`.
This provides a convenient way to specify what array types the invoker should try.
Both :class:`vtkm::cont::UnknownArrayHandle` and :class:`vtkm::cont::UncertainArrayHandle` provide a method named :func:`vtkm::cont::UnknownArrayHandle::ResetTypes` to redefine the types to try.
:func:`vtkm::cont::UncertainArrayHandle::ResetTypes` has two template parameters that are the :class:`vtkm::List`'s of value and storage types.
:func:`vtkm::cont::UnknownArrayHandle::ResetTypes` returns a new :class:`vtkm::cont::UncertainArrayHandle` with the given types.
This is a convenient way to pass these types to functions.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ResetTypes
:class:`vtkm::cont::UncertainArrayHandle` additionally has methods named :func:`vtkm::cont::UncertainArrayHandle::ResetValueTypes` and :func:`vtkm::cont::UncertainArrayHandle::ResetStorageTypes` to reset the value types and storage types, respectively, without modifying the other.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::ResetValueTypes
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::ResetStorageTypes
.. load-example:: UnknownArrayResetTypes
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Resetting the types of an :class:`vtkm::cont::UnknownArrayHandle`.
.. commonerrors::
Because it returns an :class:`vtkm::cont::UncertainArrayHandle`, you need to include :file:`vtkm/cont/UncertainArrayHandle.h` if you use :func:`vtkm::cont::UnknownArrayHandle::ResetTypes`.
This is true even if you do not directly use the returned object.
------------------------------
Accessing Truly Unknown Arrays
------------------------------
So far in :secref:`unknown-array-handle:Casting to Known Types` and :secref:`unknown-array-handle:Casting to a List of Potential Types` we explored how to access the data in an :class:`vtkm::cont::UnknownArrayHandle` when you actually know the array type or can narrow down the array type to some finite number of candidates.
But what happens if you cannot practically narrow down the types in the :class:`vtkm::cont::UnknownArrayHandle`?
For this case, :class:`vtkm::cont::UnknownArrayHandle` provides mechanisms for extracting data knowing little or nothing about the types.
Cast with Floating Point Fallback
========================================
.. index:: unknown array handle; fallback
The problem with :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` and :func:`vtkm::cont::UncertainArrayHandle::CastAndCall` is that you can only list a finite amount of value types and storage types to try.
If you encounter an :class:`vtkm::cont::UnknownArrayHandle` containing a different :class:`vtkm::cont::ArrayHandle` type, the cast and call will simply fail.
Since the compiler must create a code path for each possible :class:`vtkm::cont::ArrayHandle` type, it may not even be feasible to list all known types.
:func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` works around this problem by providing a fallback in case the contained :class:`vtkm::cont::ArrayHandle` does not match any of the types tried.
If none of the types match, then :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` will copy the data to a :class:`vtkm::cont::ArrayHandle` with :type:`vtkm::FloatDefault` values (or some compatible :class:`vtkm::Vec` with :type:`vtkm::FloatDefault` components) and basic storage.
It will then attempt to match again with this copied array.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback
.. load-example:: CastAndCallForTypesWithFloatFallback
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Cast and call a functor from an :class:`vtkm::cont::UnknownArrayHandle` with a float fallback.
In this case, we do not have to list every possible type because the array will be copied to a known type if nothing matches.
Note that when using :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback`, you still need to include an appropriate type based on :type:`vtkm::FloatDefault` in the value type list and :class:`vtkm::cont::StorageTagBasic` in the storage list so that the copied array can match.
:class:`vtkm::cont::UncertainArrayHandle` has a matching method named :func:`vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback` that does the same operation using the types specified in the :class:`vtkm::cont::UncertainArrayHandle`.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback
.. load-example:: CastAndCallWithFloatFallback
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Cast and call a functor from an :class:`vtkm::cont::UncertainArrayHandle` with a float fallback.
Extracting Components
==============================
Using a floating point fallback allows you to use arrays of unknown types in most circumstances, but it does have a few drawbacks.
First, and most obvious, is that you may not operate on the data in its native format.
If you want to preserve the integer format of data, this may not be the method.
Second, the fallback requires a copy of the data.
If :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` does not match the type of the array, it copies the array to a new type that (hopefully) can be matched.
Third, :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` still needs to match the number of components in each array value.
If the contained :class:`vtkm::cont::ArrayHandle` contains values that are :class:`vtkm::Vec`'s of length 2, then the data will be copied to an array of :type:`vtkm::Vec2f`'s.
If :type:`vtkm::Vec2f` is not included in the types to try, the cast and call will still fail.
.. index:: unknown array handle; extract component
A way to get around these problems is to extract a single component from the array.
You can use the :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` method to return an :class:`vtkm::cont::ArrayHandle` with the values for a given component for each value in the array.
The type of the returned :class:`vtkm::cont::ArrayHandle` will be the same regardless of the actual array type stored in the :class:`vtkm::cont::UnknownArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ExtractComponent
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` must be given a template argument for the base component type.
The following example extracts the first component of all :class:`vtkm::Vec` values in an :class:`vtkm::cont::UnknownArrayHandle` assuming that the component is of type :type:`vtkm::FloatDefault` (:exlineref:`ex:UnknownArrayExtractComponent:Call`).
.. load-example:: UnknownArrayExtractComponent
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting the first component of every value in an :class:`vtkm::cont::UnknownArrayHandle`.
The code in :numref:`ex:UnknownArrayExtractComponent` works with any array with values based on the default floating point type.
If the :class:`vtkm::cont::UnknownArrayHandle` has an array containing :type:`vtkm::FloatDefault`, then the returned array has all the same values.
If the :class:`vtkm::cont::UnknownArrayHandle` contains values of type :type:`vtkm::Vec3f`, then each value in the returned array will be the first component of this array.
If the :class:`vtkm::cont::UnknownArrayHandle` really contains an array with incompatible value types (such as ``vtkm::cont::ArrayHandle<vtkm::Id>``), then an :class:`vtkm::cont::ErrorBadType` will be thrown.
To check if the :class:`vtkm::cont::UnknownArrayHandle` contains an array of a compatible type, use the :func:`vtkm::cont::UnknownArrayHandle::IsBaseComponentType` method to check the component type being used as the template argument to :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsBaseComponentType
.. load-example:: UnknownArrayBaseComponentType
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Checking the base component type in an :class:`vtkm::cont::UnknownArrayHandle`.
it is also possible to get a name for the base component type (mostly for debugging purposes) with :func:`vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName
You will often need to query the number of components that can be extracted from the array.
This can be queried with :func:`vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat
This section started with the motivation of getting data from an :class:`vtkm::cont::UnknownArrayHandle` without knowing anything about the type, yet :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` still requires a type parameter.
However, by limiting the type needed to the base component type, you only need to check the base C types (standard integers and floating points) available in C++.
You do not need to know whether these components are arranged in :class:`vtkm::Vec`'s or the size of the :class:`vtkm::Vec`.
A general implementation of an algorithm might have to deal with scalars as well as :class:`vtkm::Vec`'s of size 2, 3, and 4.
If we consider operations on tensors, :class:`vtkm::Vec`'s of size 6 and 9 can be common as well.
But when using :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent`, a single condition can handle any potential :class:`vtkm::Vec` size.
Another advantage of :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` is that the type of storage does not need to be specified.
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` works with any type of :class:`vtkm::cont::ArrayHandle` storage (with some caveats).
So, :numref:`ex:UnknownArrayExtractComponent` works equally as well with :class:`vtkm::cont::ArrayHandleBasic`, :class:`vtkm::cont::ArrayHandleSOA`, :class:`vtkm::cont::ArrayHandleUniformPointCoordinates`, :class:`vtkm::cont::ArrayHandleCartesianProduct`, and many others.
Trying to capture all reasonable types of arrays could easily require hundreds of conditions, all of which and more can be captured with :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` and the roughly 12 basic C data types.
In practice, you often only really have to worry about floating point components, which further reduces the cases down to (usually) 2.
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` works by returning an :class:`vtkm::cont::ArrayHandleStride`.
This is a special :class:`vtkm::cont::ArrayHandle` that can access data buffers by skipping values at regular intervals.
This allows it to access data packed in different ways such as :class:`vtkm::cont::ArrayHandleBasic`, :class:`vtkm::cont::ArrayHandleSOA`, and many others.
That said, :class:`vtkm::cont::ArrayHandleStride` is not magic, so if it cannot directly access memory, some or all of it may be copied.
If you are attempting to use the array from :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` as an output array, pass :enumerator:`vtkm::CopyFlag::Off` as a second argument.
This will ensure that data are not copied so that any data written will go to the original array (or throw an exception if this cannot be done).
.. commonerrors::
Although :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` will technically work with any :class:`vtkm::cont::ArrayHandle` (of simple :class:`vtkm::Vec` types), it may require a very inefficient memory copy.
Pay attention if :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` issues a warning about an inefficient memory copy.
This is likely a serious performance issue, and the data should be retrieved in a different way (or better yet stored in a different way).
Extracting All Components
==============================
:numref:`ex:UnknownArrayExtractComponent` accesses the first component of each :class:`vtkm::Vec` in an array.
But in practice you usually want to operate on all components stored in the array.
A simple solution is to iterate over each component.
.. load-example:: UnknownArrayExtractComponentsMultiple
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting each component from an :class:`vtkm::cont::UnknownArrayHandle`.
To ensure that the type of the extracted component is a basic C type, the :class:`vtkm::Vec` values are "flattened."
That is, they are treated as if they are a single level :class:`vtkm::Vec`.
For example, if you have a value type of ``vtkm::Vec<vtkm::Id3, 2>``, :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` treats this type as ``vtkm::Vec<vtkm::Id, 6>``.
This allows you to extract the components as type :type:`vtkm::Id` rather than having a special case for :type:`vtkm::Id3`.
Although iterating over components works fine, it can be inconvenient.
An alternate mechanism is to use :func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents` to get all the components at once.
:func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents` works like :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` except that instead of returning an :class:`vtkm::cont::ArrayHandleStride`, it returns a special :class:`vtkm::cont::ArrayHandleRecombineVec` that behaves like an :class:`vtkm::cont::ArrayHandle` to reference all component arrays at once.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents
.. load-example:: UnknownArrayExtractArrayFromComponents
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting all components from an :class:`vtkm::cont::UnknownArrayHandle` at once.
.. commonerrors::
Although it has the same interface as other :class:`vtkm::cont::ArrayHandle`'s, :class:`vtkm::cont::ArrayHandleRecombineVec` has a special value type that breaks some conventions.
For example, when used in a worklet, the value type passed from this array to the worklet cannot be replicated.
That is, you cannot create a temporary stack value of the same type.
Because you still need to specify a base component type, you will likely still need to check several types to safely extract data from an :class:`vtkm::cont::UnknownArrayHandle` by component.
To do this automatically, you can use the :func:`vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray`.
This method behaves similarly to :func:`vtkm::cont::UncertainArrayHandle::CastAndCall` except that it internally uses :func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray
.. load-example:: UnknownArrayCallWithExtractedArray
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Calling a functor for nearly any type of array stored in an :class:`vtkm::cont::UnknownArrayHandle`.
------------------------------
Mutability
------------------------------
.. index:: unknown array handle; const
One subtle feature of :class:`vtkm::cont::UnknownArrayHandle` is that the class is, in principle, a pointer to an array pointer.
This means that the data in an :class:`vtkm::cont::UnknownArrayHandle` is always mutable even if the class is declared ``const``.
The upshot is that you can pass output arrays as constant :class:`vtkm::cont::UnknownArrayHandle` references.
.. load-example:: UnknownArrayConstOutput
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using a ``const`` :class:`vtkm::cont::UnknownArrayHandle` for a function output.
Although it seems strange, there is a good reason to allow an output :class:`vtkm::cont::UnknownArrayHandle` to be ``const``.
It allows a typed :class:`vtkm::cont::ArrayHandle` to be used as the argument to the function.
In this case, the compiler will automatically convert the :class:`vtkm::cont::ArrayHandle` to a :class:`vtkm::cont::UnknownArrayHandle`.
When C++ creates objects like this, they can only be passed a constant reference, an Rvalue reference, or by value.
So, declaring the output parameter as ``const`` :class:`vtkm::cont::UnknownArrayHandle` allows it to be used for code like this.
.. load-example:: UseUnknownArrayConstOutput
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Passing an :class:`vtkm::cont::ArrayHandle` as an output :class:`vtkm::cont::UnknownArrayHandle`.
Of course, you could also declare the output by value instead of by reference, but this has the same semantics with extra internal pointer management.
.. didyouknow::
When possible, it is better to pass a :class:`vtkm::cont::UnknownArrayHandle` as a constant reference (or by value) rather than a mutable reference, even if the array contents are going to be modified.
This allows the function to support automatic conversion of an output :class:`vtkm::cont::ArrayHandle`.
So if a constant :class:`vtkm::cont::UnknownArrayHandle` 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.
If you want to do operations like doing a shallow copy or changing the underlying type of the array, a non-constant reference is needed.

@ -1 +1 @@
2.1.9999
2.2.9999

@ -350,6 +350,8 @@ public:
SecondHandleType,
ThirdHandleType>::Superclass));
/// Construct an `ArrayHandleCartesianProduct` given arrays for the coordinates in
/// the x, y, and z diretions.
VTKM_CONT
ArrayHandleCartesianProduct(const FirstHandleType& firstArray,
const SecondHandleType& secondArray,
@ -365,14 +367,17 @@ public:
///
~ArrayHandleCartesianProduct() {}
/// Get the array for the coordinates in the x direction.
VTKM_CONT FirstHandleType GetFirstArray() const
{
return StorageType::GetArrayHandle1(this->GetBuffers());
}
/// Get the array for the coordinates in the y direction.
VTKM_CONT SecondHandleType GetSecondArray() const
{
return StorageType::GetArrayHandle2(this->GetBuffers());
}
/// Get the array for the coordinates in the z direction.
VTKM_CONT ThirdHandleType GetThirdArray() const
{
return StorageType::GetArrayHandle3(this->GetBuffers());

@ -151,6 +151,7 @@ public:
T,
StorageTagCast<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag>>));
/// Construct an `ArrayHandleCast` from a source array handle.
ArrayHandleCast(const vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
typename ArrayHandleType::StorageTag>& handle)
: Superclass(Superclass::StorageType::CreateBuffers(handle))
@ -158,11 +159,10 @@ public:
this->ValidateTypeCast<typename ArrayHandleType::ValueType>();
}
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
// Implemented so that it is defined exclusively in the control environment.
// If there is a separate device for the execution environment (for example,
// with CUDA), then the automatically generated destructor could be
// created for all devices, and it would not be valid for all devices.
~ArrayHandleCast() {}
/// \brief Returns the `ArrayHandle` that is being transformed.
@ -246,7 +246,7 @@ struct MakeArrayHandleCastImpl<T, T, ArrayType>
} // namespace detail
/// make_ArrayHandleCast is convenience function to generate an
/// `make_ArrayHandleCast` is convenience function to generate an
/// ArrayHandleCast.
///
template <typename T, typename ArrayType>

@ -390,18 +390,21 @@ struct Storage<T, vtkm::cont::StorageTagCompositeVec<StorageTag>> : Storage<T, S
} // namespace internal
/// \brief An \c ArrayHandle that combines components from other arrays.
/// @brief An `ArrayHandle` that combines components from other arrays.
///
/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that
/// `ArrayHandleCompositeVector` is a specialization of `ArrayHandle` that
/// derives its content from other arrays. It takes any number of
/// single-component \c ArrayHandle objects and mimics an array that contains
/// vectors with components that come from these delegate arrays.
///
/// The easiest way to create and type an \c ArrayHandleCompositeVector is
/// The easiest way to create and type an `ArrayHandleCompositeVector` is
/// to use the \c make_ArrayHandleCompositeVector functions.
///
/// The \c ArrayHandleExtractComponent class may be helpful when a desired
/// component is part of an \c ArrayHandle with a \c vtkm::Vec \c ValueType.
/// The `ArrayHandleExtractComponent` class may be helpful when a desired
/// component is part of an `ArrayHandle` with a `vtkm::Vec` `ValueType`.
///
/// If you are attempted to combine components that you know are stored in
/// basic `ArrayHandle`s, consider using `ArrayHandleSOA` instead.
///
template <typename... ArrayTs>
class ArrayHandleCompositeVector
@ -413,12 +416,14 @@ public:
(ArrayHandleCompositeVector<ArrayTs...>),
(typename internal::CompositeVectorTraits<ArrayTs...>::Superclass));
/// Construct an `ArrayHandleCompositeVector` from a set of component vectors.
VTKM_CONT
ArrayHandleCompositeVector(const ArrayTs&... arrays)
: Superclass(StorageType::CreateBuffers(arrays...))
{
}
/// Return the arrays of all of the components in a `vtkm::Tuple` object.
VTKM_CONT vtkm::Tuple<ArrayTs...> GetArrayTuple() const
{
return StorageType::GetArrayTuple(this->GetBuffers());

@ -58,9 +58,9 @@ struct Storage<T, vtkm::cont::StorageTagConstant> : Storage<T, StorageTagConstan
} // namespace internal
/// \brief An array handle with a constant value.
/// @brief An array handle with a constant value.
///
/// ArrayHandleConstant is an implicit array handle with a constant value. A
/// `ArrayHandleConstant` is an implicit array handle with a constant value. A
/// constant array handle is constructed by giving a value and an array length.
/// The resulting array is of the given size with each entry the same value
/// given in the constructor. The array is defined implicitly, so there it
@ -74,6 +74,7 @@ public:
(ArrayHandleConstant<T>),
(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>));
/// Construct a constant array containing the given value.
VTKM_CONT
ArrayHandleConstant(T value, vtkm::Id numberOfValues = 0)
: Superclass(internal::FunctorToArrayHandleImplicitBuffers(internal::ConstantFunctor<T>(value),
@ -81,17 +82,15 @@ public:
{
}
/// \brief Returns the constant value stored in this array.
/// @brief Returns the constant value stored in this array.
///
/// The value set in the constructor of this array is returned even if the number of values is 0.
///
VTKM_CONT T GetValue() const { return this->ReadPortal().GetFunctor()(0); }
};
/// make_ArrayHandleConstant is convenience function to generate an
/// ArrayHandleImplicit. It takes a functor and the virtual length of the
/// array.
///
/// `make_ArrayHandleConstant` is convenience function to generate an
/// ArrayHandleImplicit.
template <typename T>
vtkm::cont::ArrayHandleConstant<T> make_ArrayHandleConstant(T value, vtkm::Id numberOfValues)
{

@ -31,7 +31,7 @@ struct VTKM_ALWAYS_EXPORT StorageTagCounting
namespace internal
{
/// \brief An implicit array portal that returns an counting value.
/// \brief An implicit array portal that returns a counting value.
template <class CountingValueType>
class VTKM_ALWAYS_EXPORT ArrayPortalCounting
{
@ -48,6 +48,11 @@ public:
{
}
/// @brief Create an implicit counting array.
///
/// @param start The starting value in the first value of the array.
/// @param step The increment between sequential values in the array.
/// @param numValues The size of the array.
VTKM_EXEC_CONT
ArrayPortalCounting(ValueType start, ValueType step, vtkm::Id numValues)
: Start(start)
@ -56,15 +61,19 @@ public:
{
}
/// Returns the starting value.
VTKM_EXEC_CONT
ValueType GetStart() const { return this->Start; }
/// Returns the step value.
VTKM_EXEC_CONT
ValueType GetStep() const { return this->Step; }
/// Returns the number of values in the array.
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; }
/// Returns the value for the given index.
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const
{

@ -178,14 +178,14 @@ namespace vtkm
namespace cont
{
/// \brief A fancy ArrayHandle that turns a vector array into a scalar array by
/// @brief A fancy `ArrayHandle` that turns a vector array into a scalar array by
/// slicing out a single component of each vector.
///
/// ArrayHandleExtractComponent is a specialization of ArrayHandle. It takes an
/// input ArrayHandle with a vtkm::Vec ValueType and a component index
/// `ArrayHandleExtractComponent` is a specialization of `ArrayHandle`. It takes an
/// input `ArrayHandle` with a `vtkm::Vec` `ValueType` and a component index
/// and uses this information to expose a scalar array consisting of the
/// specified component across all vectors in the input ArrayHandle. So for a
/// given index i, ArrayHandleExtractComponent looks up the i-th vtkm::Vec in
/// specified component across all vectors in the input `ArrayHandle`. So for a
/// given index i, `ArrayHandleExtractComponent` looks up the i-th `vtkm::Vec` in
/// the index array and reads or writes to the specified component, leave all
/// other components unmodified. This is done on the fly rather than creating a
/// copy of the array.
@ -203,17 +203,20 @@ public:
typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::ComponentType,
StorageTagExtractComponent<ArrayHandleType>>));
/// Construct an `ArrayHandleExtractComponent` with a given array and component.
VTKM_CONT
ArrayHandleExtractComponent(const ArrayHandleType& array, vtkm::IdComponent component)
: Superclass(StorageType::CreateBuffers(component, array))
{
}
/// Get the component index being extracted from the source array.
VTKM_CONT vtkm::IdComponent GetComponent() const
{
return StorageType::ComponentIndex(this->GetBuffers());
}
/// Get the source array of `Vec`s to get a component out of.
VTKM_CONT ArrayHandleType GetArray() const
{
using BaseArray = vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
@ -222,8 +225,8 @@ public:
}
};
/// make_ArrayHandleExtractComponent is convenience function to generate an
/// ArrayHandleExtractComponent.
/// `make_ArrayHandleExtractComponent` is convenience function to generate an
/// `ArrayHandleExtractComponent`.
template <typename ArrayHandleType>
VTKM_CONT ArrayHandleExtractComponent<ArrayHandleType> make_ArrayHandleExtractComponent(
const ArrayHandleType& array,

@ -192,21 +192,21 @@ public:
} // namespace internal
/// \brief Fancy array handle that groups values into vectors.
/// @brief Fancy array handle that groups values into vectors.
///
/// It is sometimes the case that an array is stored such that consecutive
/// entries are meant to form a group. This fancy array handle takes an array
/// of values and a size of groups and then groups the consecutive values
/// stored in a \c Vec.
/// stored in a `vtkm::Vec`.
///
/// For example, if you have an array handle with the six values 0,1,2,3,4,5
/// and give it to a \c ArrayHandleGroupVec with the number of components set
/// to 3, you get an array that looks like it contains two values of \c Vec
/// values of size 3 with the data [0,1,2], [3,4,5].
/// and give it to a `ArrayHandleGroupVec` with the number of components set
/// to 3, you get an array that looks like it contains two values of `vtkm::Vec`
/// of size 3 with the data [0,1,2], [3,4,5].
///
/// The array of components should have a number of values that divides evenly
/// with the size of the Vec. If the components array does not divide evenly
/// into `Vec`s, then a warning will be logged and the extra component values
/// with the size of the `vtkm::Vec`. If the components array does not divide evenly
/// into `vtkm::Vec`s, then a warning will be logged and the extra component values
/// will be ignored.
///
template <typename ComponentsArrayHandleType, vtkm::IdComponent NUM_COMPONENTS>
@ -229,19 +229,21 @@ public:
using ComponentType = typename ComponentsArrayHandleType::ValueType;
/// Construct an `ArrayHandleGroupVec` with a provided components array.
VTKM_CONT
ArrayHandleGroupVec(const ComponentsArrayHandleType& componentsArray)
: Superclass(componentsArray.GetBuffers())
{
}
/// Retrieve the components array being grouped.
VTKM_CONT ComponentsArrayHandleType GetComponentsArray() const
{
return ComponentsArrayHandleType(this->GetBuffers());
}
};
/// \c make_ArrayHandleGroupVec is convenience function to generate an
/// `make_ArrayHandleGroupVec` is convenience function to generate an
/// ArrayHandleGroupVec. It takes in an ArrayHandle and the number of components
/// (as a specified template parameter), and returns an array handle with
/// consecutive entries grouped in a Vec.

@ -233,13 +233,13 @@ public:
} // namespace internal
/// \brief Fancy array handle that groups values into vectors of different sizes.
/// @brief Fancy array handle that groups values into vectors of different sizes.
///
/// It is sometimes the case that you need to run a worklet with an input or
/// output that has a different number of values per instance. For example, the
/// cells of a CellCetExplicit can have different numbers of points in each
/// cells of a `vtkm::cont::CellCetExplicit` can have different numbers of points in each
/// cell. If inputting or outputting cells of this type, each instance of the
/// worklet might need a \c Vec of a different length. This fance array handle
/// worklet might need a `vtkm::Vec` of a different length. This fancy array handle
/// takes an array of values and an array of offsets and groups the consecutive
/// values in Vec-like objects. The values are treated as tightly packed, so
/// that each Vec contains the values from one offset to the next. The last
@ -247,25 +247,25 @@ public:
///
/// For example, if you have an array handle with the 9 values
/// 0,1,2,3,4,5,6,7,8 an offsets array handle with the 4 values 0,4,6,9 and give
/// them to an \c ArrayHandleGroupVecVariable, you get an array that looks like
/// them to an `ArrayHandleGroupVecVariable`, you get an array that looks like
/// it contains three values of Vec-like objects with the data [0,1,2,3],
/// [4,5], and [6,7,8].
///
/// Note that caution should be used with `ArrayHandleRuntimeVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `VecFromPortal` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `VecFromPortal`
/// size of the `vtkm::Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `vtkm::VecFromPortal` class that can cause
/// surprises if treated as a `vtkm::Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `vtkm::VecFromPortal`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
/// like `+=` do work because they are given an existing variable to place the
/// output.)
///
/// The offsets array is often derived from a list of sizes for each of the
/// entries. You can use the convenience function \c
/// ConvertNumComponentsToOffsets to take an array of sizes (i.e. the number of
/// components for each entry) and get an array of offsets needed for \c
/// ArrayHandleGroupVecVariable.
/// entries. You can use the convenience function
/// `vtkm::cont::ConvertNumComponentsToOffsets` to take an array of sizes
/// (i.e. the number of components for each entry) and get an array of offsets
/// needed for `ArrayHandleGroupVecVariable`.
///
template <typename ComponentsArrayHandleType, typename OffsetsArrayHandleType>
class ArrayHandleGroupVecVariable
@ -292,6 +292,7 @@ public:
using ComponentType = typename ComponentsArrayHandleType::ValueType;
/// Construct an `ArrayHandleGroupVecVariable`
VTKM_CONT
ArrayHandleGroupVecVariable(const ComponentsArrayHandleType& componentsArray,
const OffsetsArrayHandleType& offsetsArray)
@ -299,18 +300,20 @@ public:
{
}
/// Return the components array providing the data for the grouped vec array.
VTKM_CONT ComponentsArrayHandleType GetComponentsArray() const
{
return StorageType::GetComponentsArray(this->GetBuffers());
}
/// Return the offsets array defining the locations and sizes of each value.
VTKM_CONT OffsetsArrayHandleType GetOffsetsArray() const
{
return StorageType::GetOffsetsArray(this->GetBuffers());
}
};
/// \c make_ArrayHandleGroupVecVariable is convenience function to generate an
/// `make_ArrayHandleGroupVecVariable` is convenience function to generate an
/// ArrayHandleGroupVecVariable. It takes in an ArrayHandle of values and an
/// array handle of offsets and returns an array handle with consecutive
/// entries grouped in a Vec.

@ -58,6 +58,7 @@ public:
VTKM_ARRAY_HANDLE_SUBCLASS_NT(ArrayHandleIndex,
(vtkm::cont::ArrayHandle<vtkm::Id, StorageTagIndex>));
/// Construct an index array containing values from 0 to `length` - 1.
VTKM_CONT
ArrayHandleIndex(vtkm::Id length)
: Superclass(

@ -254,6 +254,7 @@ public:
vtkm::cont::StorageTagPermutation<typename IndexArrayHandleType::StorageTag,
typename ValueArrayHandleType::StorageTag>>));
/// Construct a permuation array with index and value arrays.
VTKM_CONT
ArrayHandlePermutation(const IndexArrayHandleType& indexArray,
const ValueArrayHandleType& valueArray)
@ -261,11 +262,21 @@ public:
{
}
/// @brief Return the array used for indices.
///
/// The index array provides how indices get permuted. When a value is retrieved from an
/// `ArrayHandlePermutation`, an index is retrived from this index array, and this new
/// index is used to retrieve a value from the value array.
VTKM_CONT IndexArrayHandleType GetIndexArray() const
{
return StorageType::GetIndexArray(this->GetBuffers());
}
/// @brief Return the array used for values.
///
/// The index array provides how indices get permuted. When a value is retrieved from an
/// `ArrayHandlePermutation`, an index is retrived from this index array, and this new
/// index is used to retrieve a value from the value array.
VTKM_CONT ValueArrayHandleType GetValueArray() const
{
return StorageType::GetValueArray(this->GetBuffers());
@ -275,13 +286,13 @@ public:
/// make_ArrayHandleTransform is convenience function to generate an
/// ArrayHandleTransform. It takes in an ArrayHandle and a functor
/// to apply to each element of the Handle.
template <typename IndexArrayHandleType, typename ValueArrayHandleType>
VTKM_CONT vtkm::cont::ArrayHandlePermutation<IndexArrayHandleType, ValueArrayHandleType>
make_ArrayHandlePermutation(IndexArrayHandleType indexArray, ValueArrayHandleType valueArray)
{
return ArrayHandlePermutation<IndexArrayHandleType, ValueArrayHandleType>(indexArray, valueArray);
}
}
} // namespace vtkm::cont

@ -37,6 +37,22 @@ struct BoxMuller
};
} //detail
/// @brief An `ArrayHandle` that provides a source of random numbers with a standard normal distribution.
///
/// `ArrayHandleRandomStandardNormal` takes a user supplied seed and hashes it to provide
/// a sequence of numbers drawn from a random standard normal distribution. The probability
/// density function of the numbers is @f$\frac{e^{-x^2/2}}{\sqrt{2\pi}}@f$. The range of possible
/// values is technically infinite, but the probability of large positive or negative numbers
/// becomes vanishingly small.
///
/// This array uses the Box-Muller transform to pick random numbers in the stanard normal
/// distribution.
///
/// Note: In contrast to traditional random number generator,
/// `ArrayHandleRandomStandardNormal` does not have "state", i.e. multiple calls
/// the Get() method with the same index will always return the same hash value.
/// To get a new set of random bits, create a new `ArrayHandleRandomUniformBits`
/// with a different seed.
template <typename Real = vtkm::Float64>
class VTKM_ALWAYS_EXPORT ArrayHandleRandomStandardNormal
: public vtkm::cont::ArrayHandleTransform<
@ -56,6 +72,13 @@ public:
vtkm::cont::ArrayHandleRandomUniformReal<Real>>,
detail::BoxMuller>));
/// Construct an `ArrayHandleRandomStandardNormal`.
///
/// @param length Specifies the length of the generated array.
/// @param seed Provides a seed to use for the pseudorandom numbers. To prevent confusion
/// between the seed and the length, the type of the seed is a `vtkm::Vec` of size 1. To
/// specify the seed, declare it in braces. For example, to construct a random array of
/// size 50 with seed 123, use `ArrayHandleRandomStandardNormal(50, { 123 })`.
explicit ArrayHandleRandomStandardNormal(vtkm::Id length,
SeedType seed = { std::random_device{}() })
: Superclass(vtkm::cont::make_ArrayHandleZip(UniformReal{ length, seed },

@ -51,9 +51,9 @@ private:
}; // class PhiloxFunctor
} // namespace detail
/// \brief An \c ArrayHandle that provides a source of random bits
/// @brief An `ArrayHandle` that provides a source of random bits
///
/// \c ArrayHandleRandomUniformBits is a specialization of ArrayHandleImplicit.
/// `ArrayHandleRandomUniformBits` is a specialization of `ArrayHandleImplicit`.
/// It takes a user supplied seed and hash it with the a given index value. The
/// hashed value is the value of the array at that position.
///
@ -64,9 +64,9 @@ private:
/// is used as the hash function.
///
/// Note: In contrast to traditional random number generator,
/// ArrayHandleRandomUniformBits does not have "state", i.e. multiple calls
/// `ArrayHandleRandomUniformBits` does not have "state", i.e. multiple calls
/// the Get() method with the same index will always return the same hash value.
/// To ge a new set of random bits, create a new ArrayHandleRandomUniformBits
/// To get a new set of random bits, create a new `ArrayHandleRandomUniformBits`
/// with a different seed.
class VTKM_ALWAYS_EXPORT ArrayHandleRandomUniformBits
: public vtkm::cont::ArrayHandleImplicit<detail::PhiloxFunctor>
@ -77,8 +77,13 @@ public:
VTKM_ARRAY_HANDLE_SUBCLASS_NT(ArrayHandleRandomUniformBits,
(vtkm::cont::ArrayHandleImplicit<detail::PhiloxFunctor>));
/// The type of seed is specifically designed to be an vtkm::Vec<> to provide
/// type safety for the parameters so user will not transpose two integer parameters.
/// Construct an `ArrayHandleRandomUniformBits`.
///
/// @param length Specifies the length of the generated array.
/// @param seed Provides a seed to use for the pseudorandom numbers. To prevent confusion
/// between the seed and the length, the type of the seed is a `vtkm::Vec` of size 1. To
/// specify the seed, declare it in braces. For example, to construct a random array of
/// size 50 with seed 123, use `ArrayHandleRandomUniformBits(50, { 123 })`.
explicit ArrayHandleRandomUniformBits(vtkm::Id length, SeedType seed = { std::random_device{}() })
: Superclass(detail::PhiloxFunctor(seed), length)
{

@ -50,6 +50,18 @@ struct CanonicalFunctor<vtkm::Float32>
};
} // detail
/// @brief An `ArrayHandle` that provides a source of random numbers with uniform distribution.
///
/// `ArrayHandleRandomUniformReal` takes a user supplied seed and hashes it to provide
/// a sequence of numbers drawn from a random uniform distribution in the range [0, 1).
/// `ArrayHandleRandomUniformReal` is built on top of `ArrayHandleRandomUniformBits` so
/// shares its behavior with that array.
///
/// Note: In contrast to traditional random number generator,
/// `ArrayHandleRandomUniformReal` does not have "state", i.e. multiple calls
/// the Get() method with the same index will always return the same hash value.
/// To get a new set of random bits, create a new `ArrayHandleRandomUniformBits`
/// with a different seed.
template <typename Real = vtkm::Float64>
class VTKM_ALWAYS_EXPORT ArrayHandleRandomUniformReal
: public vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandleRandomUniformBits,
@ -64,6 +76,13 @@ public:
(vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandleRandomUniformBits,
detail::CanonicalFunctor<Real>>));
/// Construct an `ArrayHandleRandomUniformReal`.
///
/// @param length Specifies the length of the generated array.
/// @param seed Provides a seed to use for the pseudorandom numbers. To prevent confusion
/// between the seed and the length, the type of the seed is a `vtkm::Vec` of size 1. To
/// specify the seed, declare it in braces. For example, to construct a random array of
/// size 50 with seed 123, use `ArrayHandleRandomUniformReal(50, { 123 })`.
explicit ArrayHandleRandomUniformReal(vtkm::Id length, SeedType seed = { std::random_device{}() })
: Superclass(vtkm::cont::ArrayHandleRandomUniformBits{ length, seed },
detail::CanonicalFunctor<Real>{})

@ -587,19 +587,19 @@ public:
} // namespace internal
/// \brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `Vec`s.
/// @brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `vtkm::Vec`s.
///
/// The main intention of `ArrayHandleStride` is to pull out a component of an
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `Vec` shape.
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `vtkm::Vec` shape.
/// However, usually you want to do an operation on all the components together.
/// `ArrayHandleRecombineVec` implements the functionality to easily take a
/// group of extracted components and treat them as a single `ArrayHandle` of
/// `Vec` values.
/// `vtkm::Vec` values.
///
/// Note that caution should be used with `ArrayHandleRecombineVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// size of the `vtkm::Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `RecombineVec` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// surprises if treated as a `vtkm::Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `RecombineVec`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
@ -618,17 +618,33 @@ public:
(vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
vtkm::cont::internal::StorageTagRecombineVec>));
/// @brief Return the number of components in each value of the array.
///
/// This is also equal to the number of component arrays referenced by this
/// fancy array.
///
/// `ArrayHandleRecombineVec` always stores flat Vec values. As such, this number
/// of components is the same as the number of base components.
vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::GetNumberOfComponents(this->GetBuffers());
}
/// @brief Get the array storing the values for a particular component.
///
/// The returned array is a `vtkm::cont::ArrayHandleStride`. It is possible
/// that the returned arrays from different components reference the same area
/// of physical memory (usually referencing values interleaved with each other).
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(
vtkm::IdComponent componentIndex) const
{
return StorageType::ArrayForComponent(this->GetBuffers(), componentIndex);
}
/// @brief Add a component array.
///
/// `AppendComponentArray()` provides an easy way to build an `ArrayHandleRecombineVec`
/// by iteratively adding the component arrays.
void AppendComponentArray(
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>& array)
{

@ -204,12 +204,22 @@ public:
using MapType = typename Traits::MapType;
/// Construct an `ArrayHandleSwizzle` with a source array and a swizzle map.
/// The swizzle map is a `vtkm::Vec` containing `vtkm::IdComponent` components
/// and sized to the number of components in the array. Each value in the map
/// specifies from which component of the input the corresponding component of
/// the output should come from.
VTKM_CONT ArrayHandleSwizzle(const ArrayHandleType& array, const MapType& map)
: Superclass(array, Traits::GetFunctor(map), Traits::GetInverseFunctor(map))
{
}
};
/// Construct an `ArrayHandleSwizzle` from a provided array and swizzle map.
/// The swizzle map is a `vtkm::Vec` containing `vtkm::IdComponent` components
/// and sized to the number of components in the array. Each value in the map
/// specifies from which component of the input the corresponding component of
/// the output should come from.
template <typename ArrayHandleType, vtkm::IdComponent OutSize>
VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, OutSize> make_ArrayHandleSwizzle(
const ArrayHandleType& array,
@ -218,11 +228,14 @@ VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, OutSize> make_ArrayHandleSwizzle(
return ArrayHandleSwizzle<ArrayHandleType, OutSize>(array, map);
}
/// Construct an `ArrayHandleSwizzle` from a provided array and swizzle map.
/// The swizzle map is specified as independent function parameters after the array.
/// Each value in the map specifies from which component of the input the corresponding
/// component of the output should come from.
template <typename ArrayHandleType, typename... SwizzleIndexTypes>
VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, vtkm::IdComponent(sizeof...(SwizzleIndexTypes) + 1)>
make_ArrayHandleSwizzle(const ArrayHandleType& array,
vtkm::IdComponent swizzleIndex0,
SwizzleIndexTypes... swizzleIndices)
VTKM_CONT auto make_ArrayHandleSwizzle(const ArrayHandleType& array,
vtkm::IdComponent swizzleIndex0,
SwizzleIndexTypes... swizzleIndices)
{
return make_ArrayHandleSwizzle(array, vtkm::make_Vec(swizzleIndex0, swizzleIndices...));
}

@ -50,20 +50,23 @@ public:
ArrayHandleUniformPointCoordinates,
(vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>));
/// Create an `ArrayHandleUniformPointCoordinates` with the given specifications.
VTKM_CONT
ArrayHandleUniformPointCoordinates(vtkm::Id3 dimensions,
ValueType origin = ValueType(0.0f, 0.0f, 0.0f),
ValueType spacing = ValueType(1.0f, 1.0f, 1.0f));
/// Implemented so that it is defined exclusively in the control environment.
/// If there is a separate device for the execution environment (for example,
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
// Implemented so that it is defined exclusively in the control environment.
// If there is a separate device for the execution environment (for example,
// with CUDA), then the automatically generated destructor could be
// created for all devices, and it would not be valid for all devices.
~ArrayHandleUniformPointCoordinates();
/// Get the number of points of the uniform grid in the x, y, and z directions.
VTKM_CONT vtkm::Id3 GetDimensions() const;
/// Get the coordinates of the "lower-left" cornder of the mesh.
VTKM_CONT vtkm::Vec3f GetOrigin() const;
/// Get the spacing between points of the grid in the x, y, and z directions.
VTKM_CONT vtkm::Vec3f GetSpacing() const;
};

@ -189,6 +189,12 @@ public:
} // namespace internal
/// @brief Provided a windowed view into a `vtkm::cont::ArrayHandle`.
///
/// `ArrayHandleView` is a fancy array that wraps around another `ArrayHandle`
/// and reindexes it to provide access to a specified region of values in the
/// array. This view is specified using the offset to the first index and the
/// length of the entries to view.
template <typename ArrayHandleType>
class ArrayHandleView
: public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
@ -203,23 +209,33 @@ public:
(vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
StorageTagView<typename ArrayHandleType::StorageTag>>));
/// Create an `ArrayHandleView` over a provided source array.
///
/// @param array The source array to create a view from.
/// @param startIndex The offset in `array` to start the view.
/// @param numValues The number of values in the view.
VTKM_CONT
ArrayHandleView(const ArrayHandleType& array, vtkm::Id startIndex, vtkm::Id numValues)
: Superclass(StorageType::CreateBuffers(startIndex, numValues, array))
{
}
/// Retrieve the full array being viewed.
VTKM_CONT ArrayHandleType GetSourceArray() const
{
return this->GetStorage().GetSourceArray(this->GetBuffers());
}
/// Retrieve the start index from the array being viewed.
/// (Note, to get the number of values, simply call the `GetNumberOfValues`
/// method from the superclass.)
VTKM_CONT vtkm::Id GetStartIndex() const
{
return this->GetStorage().GetStartIndex(this->GetBuffers());
}
};
/// @brief Construct a `vtkm::cont::ArrayHandleView` from a source array.
template <typename ArrayHandleType>
ArrayHandleView<ArrayHandleType> make_ArrayHandleView(const ArrayHandleType& array,
vtkm::Id startIndex,

@ -267,13 +267,16 @@ public:
(ArrayHandleZip<FirstHandleType, SecondHandleType>),
(typename internal::ArrayHandleZipTraits<FirstHandleType, SecondHandleType>::Superclass));
/// Create `ArrayHandleZip` with two arrays.
VTKM_CONT
ArrayHandleZip(const FirstHandleType& firstArray, const SecondHandleType& secondArray)
: Superclass(StorageType::CreateBuffers(firstArray, secondArray))
{
}
/// Returns the the array for the first part of the zip pair.
FirstHandleType GetFirstArray() const { return StorageType::GetFirstArray(this->GetBuffers()); }
/// Returns the the array for the second part of the zip pair.
SecondHandleType GetSecondArray() const
{
return StorageType::GetSecondArray(this->GetBuffers());

@ -35,7 +35,7 @@ namespace cont
/// @param[in] componentsArraySize (optional) a reference to a \c vtkm::Id and is filled with the
/// expected size of the component values array.
///
/// \param[in] device (optional) specifies the device on which to run the conversion.
/// @param[in] device (optional) specifies the device on which to run the conversion.
///
/// Note that this function is pre-compiled for some set of `ArrayHandle` types. If you get a
/// warning about an inefficient conversion (or the operation fails outright), you might need to

@ -17,6 +17,7 @@
#include <vtkm/thirdparty/diy/environment.h>
#include <cstdlib>
#include <memory>
#include <sstream>
@ -123,7 +124,7 @@ InitializeResult Initialize(int& argc, char* argv[], InitializeOptions opts)
}
else
{
vtkm::cont::InitLogging(argc, argv, loggingFlag);
vtkm::cont::InitLogging(argc, argv, loggingFlag, "VTKM_LOG_LEVEL");
}
if (!vtkmdiy::mpi::environment::initialized())
{
@ -225,37 +226,70 @@ InitializeResult Initialize(int& argc, char* argv[], InitializeOptions opts)
vtkm::cont::DeviceAdapterTagAny{}, runtimeDeviceOptions, argc, argv);
}
// Check for device on command line.
if (options[opt::OptionIndex::DEVICE])
{
const char* arg = options[opt::OptionIndex::DEVICE].arg;
auto id = vtkm::cont::make_DeviceAdapterId(arg);
if (id != vtkm::cont::DeviceAdapterTagAny{})
config.Device = vtkm::cont::make_DeviceAdapterId(arg);
}
// If not on command line, check for device in environment variable.
if (config.Device == vtkm::cont::DeviceAdapterTagUndefined{})
{
const char* deviceEnv = std::getenv("VTKM_DEVICE");
if (deviceEnv != nullptr)
{
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(id);
auto id = vtkm::cont::make_DeviceAdapterId(std::getenv("VTKM_DEVICE"));
if (VtkmDeviceArg::DeviceIsAvailable(id))
{
config.Device = id;
}
else
{
// Got invalid device. Log an error, but continue to do the default action for
// the device (i.e., ignore the environment variable setting).
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Invalid device `"
<< deviceEnv
<< "` specified in VTKM_DEVICE environment variable. Ignoring.");
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Valid devices are: " << VtkmDeviceArg::GetValidDeviceNames());
}
}
}
// If still not defined, check to see if "any" device should be added.
if ((config.Device == vtkm::cont::DeviceAdapterTagUndefined{}) &&
(opts & InitializeOptions::DefaultAnyDevice) != InitializeOptions::None)
{
config.Device = vtkm::cont::DeviceAdapterTagAny{};
}
// Set the state for the device selected.
if (config.Device == vtkm::cont::DeviceAdapterTagUndefined{})
{
if ((opts & InitializeOptions::RequireDevice) != InitializeOptions::None)
{
auto devices = VtkmDeviceArg::GetValidDeviceNames();
VTKM_LOG_S(vtkm::cont::LogLevel::Fatal, "Device not given on command line.");
std::cerr << "Target device must be specified via --vtkm-device.\n"
"Valid devices: "
<< devices << std::endl;
if ((opts & InitializeOptions::AddHelp) != InitializeOptions::None)
{
std::cerr << config.Usage;
}
exit(1);
}
else
{
vtkm::cont::GetRuntimeDeviceTracker().Reset();
// No device specified. Do nothing and let VTK-m decide what it is going to do.
}
config.Device = id;
}
else if ((opts & InitializeOptions::DefaultAnyDevice) != InitializeOptions::None)
else if (config.Device == vtkm::cont::DeviceAdapterTagAny{})
{
vtkm::cont::GetRuntimeDeviceTracker().Reset();
config.Device = vtkm::cont::DeviceAdapterTagAny{};
}
else if ((opts & InitializeOptions::RequireDevice) != InitializeOptions::None)
else
{
auto devices = VtkmDeviceArg::GetValidDeviceNames();
VTKM_LOG_S(vtkm::cont::LogLevel::Error, "Device not given on command line.");
std::cerr << "Target device must be specified via --vtkm-device.\n"
"Valid devices: "
<< devices << std::endl;
if ((opts & InitializeOptions::AddHelp) != InitializeOptions::None)
{
std::cerr << config.Usage;
}
exit(1);
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(config.Device);
}

@ -30,7 +30,7 @@
#endif // VTKM_ENABLE_LOGGING
#include <cassert>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <stdexcept>
@ -108,7 +108,10 @@ namespace cont
{
VTKM_CONT
void InitLogging(int& argc, char* argv[], const std::string& loggingFlag)
void InitLogging(int& argc,
char* argv[],
const std::string& loggingFlag,
const std::string& loggingEnv)
{
SetLogLevelName(vtkm::cont::LogLevel::Off, "Off");
SetLogLevelName(vtkm::cont::LogLevel::Fatal, "FATL");
@ -130,8 +133,16 @@ void InitLogging(int& argc, char* argv[], const std::string& loggingFlag)
loguru::set_verbosity_to_name_callback(&verbosityToNameCallback);
loguru::set_name_to_verbosity_callback(&nameToVerbosityCallback);
// Set the default log level to warning
SetStderrLogLevel(vtkm::cont::LogLevel::Warn);
const char* envLevel = std::getenv(loggingEnv.c_str());
if (envLevel != nullptr)
{
SetStderrLogLevel(envLevel);
}
else
{
// Set the default log level to warning
SetStderrLogLevel(vtkm::cont::LogLevel::Warn);
}
loguru::init(argc, argv, loggingFlag.c_str());
}
#else // VTKM_ENABLE_LOGGING

@ -371,7 +371,10 @@ enum class LogLevel
*/
VTKM_CONT_EXPORT
VTKM_CONT
void InitLogging(int& argc, char* argv[], const std::string& loggingFlag = "--vtkm-log-level");
void InitLogging(int& argc,
char* argv[],
const std::string& loggingFlag = "--vtkm-log-level",
const std::string& loggingEnv = "VTKM_LOG_LEVEL");
VTKM_CONT_EXPORT
VTKM_CONT
void InitLogging();

@ -109,10 +109,10 @@ public:
/// \brief Call a functor using the underlying array type with a float cast fallback.
///
/// `CastAndCallWithFloatFallback` attempts to cast the held array to a specific value type,
/// `CastAndCallWithFloatFallback()` attempts to cast the held array to a specific value type,
/// and then calls the given functor with the cast array. If the underlying array
/// does not match any of the requested array types, the array is copied to a new
/// `ArrayHandleBasic` with `FloatDefault` components in its value and attempts to
/// `ArrayHandleBasic` with `vtkm::FloatDefault` components in its value and attempts to
/// cast to those types.
///
template <typename Functor, typename... Args>

@ -397,7 +397,7 @@ inline std::shared_ptr<UnknownAHContainer> MakeUnknownAHContainerFunctor::operat
template <typename ValueTypeList, typename StorageTypeList>
class UncertainArrayHandle;
/// \brief An ArrayHandle of an unknown value type and storage.
/// @brief An ArrayHandle of an unknown value type and storage.
///
/// `UnknownArrayHandle` holds an `ArrayHandle` object using runtime polymorphism
/// to manage different value and storage types rather than compile-time templates.
@ -408,14 +408,14 @@ class UncertainArrayHandle;
/// types.
///
/// To interface between the runtime polymorphism and the templated algorithms
/// in VTK-m, `UnknownArrayHandle` contains a method named `CastAndCallForTypes`
/// in VTK-m, `UnknownArrayHandle` contains a method named `CastAndCallForTypes()`
/// that determines the correct type from some known list of value types and
/// storage. This mechanism is used internally by VTK-m's worklet invocation
/// mechanism to determine the type when running algorithms.
///
/// If the `UnknownArrayHandle` is used in a context where the possible array
/// types can be whittled down to a finite list (or you have to), you can
/// specify lists of value types and storage using the `ResetTypesAndStorage`
/// specify lists of value types and storage using the `ResetTypesAndStorage()`
/// method. This will convert this object to an `UncertainArrayHandle` of the
/// given types. In cases where a finite set of types need to specified but
/// there is no known subset, `VTKM_DEFAULT_TYPE_LIST` and
@ -444,7 +444,7 @@ public:
{
}
/// \brief Returns whether an array is stored in this `UnknownArrayHandle`.
/// @brief Returns whether an array is stored in this `UnknownArrayHandle`.
///
/// If the `UnknownArrayHandle` is constructed without an `ArrayHandle`, it
/// will not have an underlying type, and therefore the operations will be
@ -452,7 +452,7 @@ public:
/// `ArrayHandle`.
VTKM_CONT bool IsValid() const;
/// \brief Create a new array of the same type as this array.
/// @brief Create a new array of the same type as this array.
///
/// This method creates a new array that is the same type as this one and
/// returns a new `UnknownArrayHandle` for it. This method is convenient when
@ -460,7 +460,7 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstance() const;
/// \brief Create a new `ArrayHandleBasic` with the same `ValueType` as this array.
/// @brief Create a new `ArrayHandleBasic` with the same `ValueType` as this array.
///
/// This method creates a new `ArrayHandleBasic` that has the same `ValueType` as the
/// array held by this one and returns a new `UnknownArrayHandle` for it. This method
@ -469,7 +469,7 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstanceBasic() const;
/// \brief Create a new `ArrayHandleBasic` with the base component of `FloatDefault`
/// @brief Create a new `ArrayHandleBasic` with the base component of `vtkm::FloatDefault`
///
/// This method creates a new `ArrayHandleBasic` that has a `ValueType` that is similar
/// to the array held by this one except that the base component type is replaced with
@ -487,22 +487,22 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstanceFloatBasic() const;
/// \brief Returns the name of the value type stored in the array.
/// @brief Returns the name of the value type stored in the array.
///
/// Returns an empty string if no array is stored.
VTKM_CONT std::string GetValueTypeName() const;
/// \brief Returns the name of the base component of the value type stored in the array.
/// @brief Returns the name of the base component of the value type stored in the array.
///
/// Returns an empty string if no array is stored.
VTKM_CONT std::string GetBaseComponentTypeName() const;
/// \brief Returns the name of the storage tag for the array.
/// @brief Returns the name of the storage tag for the array.
///
/// Returns an empty string if no array is stored.
VTKM_CONT std::string GetStorageTypeName() const;
/// \brief Returns a string representation of the underlying data type.
/// @brief Returns a string representation of the underlying data type.
///
/// The returned string will be of the form `vtkm::cont::ArrayHandle<T, S>` rather than the name
/// of an actual subclass. If no array is stored, an empty string is returned.
@ -525,7 +525,7 @@ public:
return this->IsStorageTypeImpl(typeid(StorageType));
}
/// \brief Returns true if this array's `ValueType` has the provided base component type.
/// @brief Returns true if this array's `ValueType` has the provided base component type.
///
/// The base component type is the recursive component type of any `Vec`-like object. So
/// if the array's `ValueType` is `vtkm::Vec<vtkm::Float32, 3>`, then the base component
@ -542,17 +542,17 @@ public:
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
}
/// \brief Returns true if this array matches the ArrayHandleType template argument.
/// @brief Returns true if this array matches the ArrayHandleType template argument.
///
/// Note that `UnknownArrayHandle` has some special handling for `ArrayHandleCast` and
/// `ArrayHandleMultiplexer`. If you stored an array of one of these types into an
/// `UnknownArrayHandle`, the type of the underlying array will change and `IsType`
/// `UnknownArrayHandle`, the type of the underlying array will change and `IsType()`
/// will fail. However, you can still get the array back out as that type using
/// `AsArrayHandle`.
///
/// Use the `CanConvert` method instead to determine if the `UnknownArrayHandle`
/// Use the `CanConvert()` method instead to determine if the `UnknownArrayHandle`
/// contains an array that "matches" the array of a given type. Under most
/// circumstances, you should prefer `CanConvert` over `IsType`.
/// circumstances, you should prefer `CanConvert()` over `IsType()`.
///
template <typename ArrayHandleType>
VTKM_CONT bool IsType() const
@ -562,7 +562,7 @@ public:
this->IsStorageType<typename ArrayHandleType::StorageTag>());
}
/// \brief Assigns potential value and storage types.
/// @brief Assigns potential value and storage types.
///
/// Calling this method will return an `UncertainArrayHandle` with the provided
/// value and storage type lists. The returned object will hold the same
@ -575,11 +575,11 @@ public:
NewValueTypeList = NewValueTypeList{},
NewStorageTypeList = NewStorageTypeList{}) const;
/// \brief Returns the number of values in the array.
/// @brief Returns the number of values in the array.
///
VTKM_CONT vtkm::Id GetNumberOfValues() const;
/// \brief Returns the number of components for each value in the array.
/// @brief Returns the number of components for each value in the array.
///
/// If the array holds `vtkm::Vec` objects, this will return the number of components
/// in each value. If the array holds a basic C type (such as `float`), this will return 1.
@ -588,7 +588,7 @@ public:
///
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
/// \brief Returns the total number of components for each value in the array.
/// @brief Returns the total number of components for each value in the array.
///
/// If the array holds `vtkm::Vec` objects, this will return the total number of components
/// in each value assuming the object is flattened out to one level of `Vec` objects.
@ -606,21 +606,19 @@ public:
///
VTKM_CONT vtkm::IdComponent GetNumberOfComponentsFlat() const;
/// \brief Reallocate the data in the array.
/// @brief Reallocate the data in the array.
///
/// The allocation works the same as the `Allocate` method of `vtkm::cont::ArrayHandle`.
///
/// @{
/// The allocation works the same as the `Allocate()` method of `vtkm::cont::ArrayHandle`.
VTKM_CONT void Allocate(vtkm::Id numValues,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token) const;
/// @copydoc Allocate
VTKM_CONT void Allocate(vtkm::Id numValues, vtkm::CopyFlag preserve = vtkm::CopyFlag::Off) const;
/// @}
/// \brief Determine if the contained array can be passed to the given array type.
/// @brief Determine if the contained array can be passed to the given array type.
///
/// This method will return true if calling `AsArrayHandle` of the given type will
/// succeed. The result is similar to `IsType`, and if `IsType` returns true, then
/// This method will return true if calling `AsArrayHandle()` of the given type will
/// succeed. The result is similar to `IsType()`, and if `IsType()` returns true, then
/// this will return true. However, this method will also return true for other
/// types such as an `ArrayHandleMultiplexer` that can contain the array.
///
@ -651,24 +649,23 @@ private:
}
public:
///@{
/// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
/// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
///
/// Throws a `vtkm::cont::ErrorBadType` if the stored array cannot be stored in the given
/// array type. Use the `CanConvert()` method to determine if the array can be returned
/// with the given type.
template <typename T, typename S>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
{
this->BaseAsArrayHandle(array);
}
/// @copydoc AsArrayHandle
template <typename T>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const;
/// @copydoc AsArrayHandle
template <typename T, typename... Ss>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;
/// @copydoc AsArrayHandle
template <typename TargetT, typename SourceT, typename SourceS>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array) const
@ -677,7 +674,7 @@ public:
array = vtkm::cont::ArrayHandleCast<TargetT, ContainedArrayType>(
this->AsArrayHandle<ContainedArrayType>());
}
/// @copydoc AsArrayHandle
template <typename T>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& array) const
@ -697,7 +694,7 @@ public:
this->BaseAsArrayHandle(array);
}
}
/// @copydoc AsArrayHandle
template <typename ArrayType>
VTKM_CONT ArrayType AsArrayHandle() const
{
@ -706,12 +703,12 @@ public:
this->AsArrayHandle(array);
return array;
}
///@}
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
/// \brief Deep copies data from another `UnknownArrayHandle`.
/// @brief Deep copies data from another `UnknownArrayHandle`.
///
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
///
@ -720,60 +717,60 @@ public:
///
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source);
/// \brief Deep copies data from another `UnknownArrayHandle`.
/// @brief Deep copies data from another `UnknownArrayHandle`.
///
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
///
/// If this object does not point to an existing `ArrayHandle`, this const version
/// of `DeepCopyFrom` throws an exception.
/// of `DeepCopyFrom()` throws an exception.
///
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source) const;
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
/// @brief Attempts a shallow copy of an array or a deep copy if that is not possible.
///
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type
/// or does not point to any `ArrayHandle` at all. If this is not possible, then
/// the array is deep copied.
///
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
/// This method is roughly equivalent to the `vtkm::cont::ArrayCopyShallowIfPossible()` function
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
/// having to use a device compiler (whereas `vtkm::cont::ArrayCopyShallowIfPossible()` does require
/// a device device compiler).
///
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source);
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
/// @brief Attempts a shallow copy of an array or a deep copy if that is not possible.
///
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type.
/// If the types are incompatible, then the array is deep copied.
///
/// If this object does not point to an existing `ArrayHandle`, this const version
/// of `CopyShallowIfPossible` throws an exception.
/// of `CopyShallowIfPossible()` throws an exception.
///
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
/// This method is roughly equivalent to the `vtkm::cont::ArrayCopyShallowIfPossible()` function
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
/// having to use a device compiler (whereas `vtkm::cont::ArrayCopyShallowIfPossible()` does require
/// a device device compiler).
///
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source) const;
/// \brief Extract a component of the array.
/// @brief Extract a component of the array.
///
/// This method returns an array that holds the data for a given flat component of the data.
/// The `BaseComponentType` has to be specified and must match the contained array (i.e.
/// the result of `IsBaseComponentType` must succeed for the given type).
/// the result of `IsBaseComponentType()` must succeed for the given type).
///
/// This method treats each value in the array as a flat `Vec` even if it is a `Vec` of
/// `Vec`s. For example, if the array actually holds values of type `Vec<Vec<T, 3>, 2>`,
/// it is treated as if it holds a `Vec<T, 6>`. See `vtkm::VecFlat` for details on how
/// vectors are flattened.
/// This method treats each value in the array as a flat `vtkm::Vec` even if it is a
/// `vtkm::Vec` of `Vec`s. For example, if the array actually holds values of type
/// `vtkm::Vec<vtkm::Vec<T, 3>, 2>`, it is treated as if it holds a `Vec<T, 6>`. See
/// `vtkm::VecFlat` for details on how vectors are flattened.
///
/// The point of using `ExtractComponent` over `AsArrayHandle` is that it drastically reduces
/// the amount of types you have to try. Most of the type the base component type is one of
/// The point of using `ExtractComponent()` over `AsArrayHandle()` is that it drastically reduces
/// the amount of types you have to try. Most of the time the base component type is one of
/// the basic C types (i.e. `int`, `long`, `float`, etc.). You do not need to know what shape
/// the containing `Vec` is in, nor do you need to know the actual storage of the array.
/// the containing `vtkm::Vec` is in, nor do you need to know the actual storage of the array.
///
/// Note that the type of the array returned is `ArrayHandleStride`. Using this type of
/// array handle has a slight overhead over basic arrays like `ArrayHandleBasic` and
@ -804,38 +801,39 @@ public:
return ComponentArrayType(buffers);
}
/// \brief Extract the array knowing only the component type of the array.
/// @brief Extract the array knowing only the component type of the array.
///
/// This method returns an `ArrayHandle` that points to the data in the array. This method
/// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
/// differs from `AsArrayHandle()` because you do not need to know the exact `ValueType` and
/// `StorageTag` of the array. Instead, you only need to know the base component type.
///
/// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
/// `ExtractArrayFromComponents()` works by calling the `ExtractComponent()` method and then
/// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
/// type of the underlying array as well as any `Vec` structure of the value type. However,
/// it also places some limitations on how the data can be pulled from the data.
///
/// First, you have to specify the base component type. This must match the data in the
/// underlying array (as reported by `IsBaseComponentType`).
/// underlying array (as reported by `IsBaseComponentType()`).
///
/// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
/// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
/// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
/// array has a `ValueType` of `vtkm::Vec<vtkm::Vec<T, 3>, 3>`, then this method will treat
/// the data as if it was `vtkm::Vec<T, 9>`. There is no way to get an array with `vtkm::Vec`
/// of `vtkm::Vec` values.
///
/// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
/// determined at runtime, that can break many assumptions of using `Vec` objects. The
/// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
/// to behave like that. The type should behave mostly like a `Vec`, but will have some
/// determined at runtime, that can break many assumptions of using `vtkm::Vec` objects. The
/// type is not going to be a `vtkm::Vec<T,N>` type but rather an internal class that is intended
/// to behave like that. The type should behave mostly like a `vtkm::Vec`, but will have some
/// differences that can lead to unexpected behavior. For example, this `Vec`-like object
/// will not have a `NUM_COMPONENTS` constant static expression because it is not known
/// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
/// at compile time. (Use the `GetNumberOfComponents()` method instead.) And for the same
/// reason you will not be able to pass these objects to classes overloaded or templated
/// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
/// Thus, you will likely have to iterate over all components rather than do operations on
/// the whole `Vec`.
///
/// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
/// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
/// Fourth, because `ExtractArrayFromComponents()` uses `ExtractComponent()` to pull data from
/// the array (which in turn uses `ArrayExtractComponent()`), there are some `ArrayHandle` types
/// that will require copying data to a new array. This could be problematic in cases where
/// you want to write to the array. To prevent data from being copied, set the optional
/// `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
@ -858,9 +856,9 @@ public:
return result;
}
/// \brief Call a functor using the underlying array type.
/// @brief Call a functor using the underlying array type.
///
/// `CastAndCallForTypes` attempts to cast the held array to a specific value type,
/// `CastAndCallForTypes()` attempts to cast the held array to a specific value type,
/// and then calls the given functor with the cast array. You must specify
/// the `TypeList` and `StorageList` as template arguments.
///
@ -870,9 +868,9 @@ public:
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;
/// \brief Call a functor using the underlying array type with a float cast fallback.
/// @brief Call a functor using the underlying array type with a float cast fallback.
///
/// `CastAndCallForTypesWithFloatFallback` attempts to cast the held array to a specific
/// `CastAndCallForTypesWithFloatFallback()` attempts to cast the held array to a specific
/// value type, and then calls the given functor with the cast array. You must specify
/// the `TypeList` and `StorageList` as template arguments.
///
@ -880,28 +878,28 @@ public:
/// passed to the functor after the converted `ArrayHandle`.
///
/// If the underlying array does not match any of the requested array types, the
/// array is copied to a new `ArrayHandleBasic` with `FloatDefault` components
/// array is copied to a new `ArrayHandleBasic` with `vtkm::FloatDefault` components
/// in its value and attempts to cast to those types.
///
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
VTKM_CONT void CastAndCallForTypesWithFloatFallback(Functor&& functor, Args&&... args) const;
/// \brief Call a functor on an array extracted from the components.
/// @brief Call a functor on an array extracted from the components.
///
/// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
/// `CastAndCallWithExtractedArray()` behaves similarly to `CastAndCallForTypes()`.
/// It converts the contained data to an `ArrayHandle` and calls a functor with
/// that `ArrayHandle` (and any number of optionally specified arguments).
///
/// The advantage of `CastAndCallWithExtractedArray` is that you do not need to
/// The advantage of `CastAndCallWithExtractedArray()` is that you do not need to
/// specify any `TypeList` or `StorageList`. Instead, it internally uses
/// `ExtractArrayFromComponents` to work with most `ArrayHandle` types with only
/// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes`
/// `ExtractArrayFromComponents()` to work with most `ArrayHandle` types with only
/// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes()`
/// with, for example, `VTKM_DEFAULT_TYPE_LIST` and `VTKM_DEFAULT_STORAGE_LIST`
/// results in many more instances of the functor but handling many fewer types
/// of `ArrayHandle`.
///
/// There are, however, costs to using this method. Details of these costs are
/// documented for the `ExtractArrayFromComponents` method, but briefly they
/// documented for the `ExtractArrayFromComponents()` method, but briefly they
/// are that `Vec` types get flattened, the resulting array has a strange `Vec`-like
/// value type that has many limitations on its use, there is an overhead for
/// retrieving each value from the array, and there is a potential that data
@ -919,6 +917,7 @@ public:
///
VTKM_CONT void ReleaseResources() const;
/// Prints a summary of the array's type, size, and contents.
VTKM_CONT void PrintSummary(std::ostream& out, bool full = false) const;
};

@ -186,30 +186,30 @@ VTKM_CONT vtkm::cont::PartitionedDataSet SelectTopVolumeContoursFilter::DoExecut
branch_top_volume_master.foreach ([&](SelectTopVolumeContoursBlock* b,
const vtkmdiy::Master::ProxyWithLink&) {
vtkm::cont::Field BranchVolumeField(
"BranchVolume", vtkm::cont::Field::Association::WholeDataSet, b->BranchVolume);
"BranchVolume", vtkm::cont::Field::Association::WholeDataSet, b->tData.BranchVolume);
outputDataSets[b->LocalBlockNo].AddField(BranchVolumeField);
vtkm::cont::Field BranchSaddleEpsilonField(
"BranchSaddleEpsilon", vtkm::cont::Field::Association::WholeDataSet, b->BranchSaddleEpsilon);
"BranchSaddleEpsilon", vtkm::cont::Field::Association::WholeDataSet, b->tData.BranchSaddleEpsilon);
outputDataSets[b->LocalBlockNo].AddField(BranchSaddleEpsilonField);
vtkm::cont::Field TopVolBranchUpperEndField("TopVolumeBranchUpperEnd",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchUpperEndGRId);
b->tData.TopVolumeBranchUpperEndGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchUpperEndField);
vtkm::cont::Field TopVolBranchLowerEndField("TopVolumeBranchLowerEnd",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchLowerEndGRId);
b->tData.TopVolumeBranchLowerEndGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchLowerEndField);
vtkm::cont::Field TopVolumeBranchGRIdsField("TopVolumeBranchGlobalRegularIds",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchRootGRId);
b->tData.TopVolumeBranchRootGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolumeBranchGRIdsField);
vtkm::cont::Field TopVolBranchVolumeField("TopVolumeBranchVolume",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchVolume);
b->tData.TopVolumeBranchVolume);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchVolumeField);
vtkm::cont::Field TopVolBranchSaddleEpsilonField("TopVolumeBranchSaddleEpsilon",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchSaddleEpsilon);
b->tData.TopVolumeBranchSaddleEpsilon);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchSaddleEpsilonField);
vtkm::cont::Field IsosurfaceEdgeFromField(
@ -243,7 +243,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet SelectTopVolumeContoursFilter::DoExecut
"TopVolumeBranchSaddleIsoValue", vtkm::cont::Field::Association::WholeDataSet, inArray);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchSaddleIsoValueField);
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
});

@ -73,9 +73,9 @@ public:
this->isMarchingCubes = marchingCubes;
}
VTKM_CONT const vtkm::Id GetSavedBranches() { return this->nSavedBranches; }
VTKM_CONT const bool GetMarchingCubes() { return this->isMarchingCubes; }
VTKM_CONT const vtkm::cont::LogLevel GetTimingsLogLevel() { return this->TimingsLogLevel; }
VTKM_CONT vtkm::Id GetSavedBranches() { return this->nSavedBranches; }
VTKM_CONT bool GetMarchingCubes() { return this->isMarchingCubes; }
VTKM_CONT vtkm::cont::LogLevel GetTimingsLogLevel() { return this->TimingsLogLevel; }
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet&) override;

@ -97,7 +97,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Block " << b->GlobalBlockId << " enqueue to Block " << target.gid);
#endif
auto extraMaximaBranchOrderPortal = b->ExtraMaximaBranchOrder.ReadPortal();
auto extraMaximaBranchOrderPortal = b->tData.ExtraMaximaBranchOrder.ReadPortal();
vtkm::Id nExtraMaxBranches = extraMaximaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMaxBranches);
@ -112,14 +112,14 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
for (vtkm::Id branch = 0; branch < nExtraMaxBranches; ++branch)
rp.enqueue<ValueType>(target, extraMaxBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMaximaBranchIsoValue.GetNumberOfValues())
b->ExtraMaximaBranchIsoValue
if (b->tData.ExtraMaximaBranchIsoValue.GetNumberOfValues())
b->tData.ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
// rp.enqueue(target, b->ExtraMaximaBranchOrder);
// rp.enqueue(target, b->ExtraMaximaBranchIsoValue);
// rp.enqueue(target, b->tData.ExtraMaximaBranchOrder);
// rp.enqueue(target, b->tData.ExtraMaximaBranchIsoValue);
auto extraMinimaBranchOrderPortal = b->ExtraMinimaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = b->tData.ExtraMinimaBranchOrder.ReadPortal();
vtkm::Id nExtraMinBranches = extraMinimaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMinBranches);
@ -134,12 +134,12 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
for (vtkm::Id branch = 0; branch < nExtraMinBranches; ++branch)
rp.enqueue<ValueType>(target, extraMinBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMinimaBranchIsoValue.GetNumberOfValues())
b->ExtraMinimaBranchIsoValue
if (b->tData.ExtraMinimaBranchIsoValue.GetNumberOfValues())
b->tData.ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);
// rp.enqueue(target, b->ExtraMinimaBranchOrder);
// rp.enqueue(target, b->ExtraMinimaBranchIsoValue);
// rp.enqueue(target, b->tData.ExtraMinimaBranchOrder);
// rp.enqueue(target, b->tData.ExtraMinimaBranchIsoValue);
}
}
}
@ -159,8 +159,8 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
"Combining local block " << b->GlobalBlockId << " with incoming block "
<< incomingGlobalBlockId);
#endif
vtkm::Id nSelfMaxBranch = b->ExtraMaximaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMinBranch = b->ExtraMinimaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMaxBranch = b->tData.ExtraMaximaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMinBranch = b->tData.ExtraMinimaBranchOrder.GetNumberOfValues();
// dequeue the data from other blocks.
// nExtraMaximaBranches (incoming)
@ -216,7 +216,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMaxBranchOrder", b->ExtraMaximaBranchOrder, -1, rs);
"selfMaxBranchOrder", b->tData.ExtraMaximaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -227,7 +227,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<true>
updateValueOnMaxBranch;
invoke(updateValueOnMaxBranch,
b->ExtraMaximaBranchOrder,
b->tData.ExtraMaximaBranchOrder,
inArray,
incomingMaxBranchOrder,
incomingMaxBranchIsoValue);
@ -238,7 +238,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
rs << "After update, block " << b->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMaxBranchOrder", b->ExtraMaximaBranchOrder, -1, rs);
"selfMaxBranchOrder", b->tData.ExtraMaximaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -246,7 +246,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
#endif
};
if (nSelfMaxBranch > 0 && nIncomingMaxBranch > 0)
b->ExtraMaximaBranchIsoValue
b->tData.ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
@ -296,7 +296,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMinBranchOrder", b->ExtraMinimaBranchOrder, -1, rs);
"selfMinBranchOrder", b->tData.ExtraMinimaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -307,7 +307,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<false>
updateValueOnMinBranch;
invoke(updateValueOnMinBranch,
b->ExtraMinimaBranchOrder,
b->tData.ExtraMinimaBranchOrder,
inArray,
incomingMinBranchOrder,
incomingMinBranchIsoValue);
@ -318,7 +318,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
rs << "After update, block " << b->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMinBranchOrder", b->ExtraMinimaBranchOrder, -1, rs);
"selfMinBranchOrder", b->tData.ExtraMinimaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -326,7 +326,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
#endif
};
if (nSelfMinBranch > 0 && nIncomingMinBranch > 0)
b->ExtraMinimaBranchIsoValue
b->tData.ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);

@ -77,12 +77,6 @@ namespace scalar_topology
namespace internal
{
struct IsNegativeDebug
{
VTKM_EXEC_CONT IsNegativeDebug() {}
VTKM_EXEC_CONT bool operator()(vtkm::Id x) const { return x < 0; }
};
SelectTopVolumeContoursBlock::SelectTopVolumeContoursBlock(vtkm::Id localBlockNo, int globalBlockId)
: LocalBlockNo(localBlockNo)
, GlobalBlockId(globalBlockId)
@ -161,7 +155,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
vtkm::cont::ArrayHandle<ValueType> branchSaddleIsoValue;
branchSaddleIsoValue.Allocate(isLowerLeaf.GetNumberOfValues());
this->BranchSaddleEpsilon.Allocate(isLowerLeaf.GetNumberOfValues());
tData.BranchSaddleEpsilon.Allocate(isLowerLeaf.GetNumberOfValues());
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateInfoByBranchDirectionWorklet<
ValueType>
@ -175,9 +169,9 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
isUpperLeaf,
inArray,
lowerEndValue,
this->BranchSaddleEpsilon,
tData.BranchSaddleEpsilon,
branchSaddleIsoValue);
this->BranchSaddleIsoValue = branchSaddleIsoValue;
tData.BranchSaddleIsoValue = branchSaddleIsoValue;
};
upperEndValue.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
@ -224,7 +218,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
#endif
vtkm::cont::Algorithm::Copy(branchVolume, this->BranchVolume);
vtkm::cont::Algorithm::Copy(branchVolume, tData.BranchVolume);
const vtkm::Id nBranches = lowerEndSuperarcId.GetNumberOfValues();
vtkm::cont::ArrayHandleIndex branchesIdx(nBranches);
@ -233,7 +227,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
// sort the branch volume
vtkm::cont::Algorithm::SortByKey(branchVolume, sortedBranches, vtkm::SortGreater());
vtkm::cont::Algorithm::Copy(sortedBranches, this->SortedBranchByVolume);
vtkm::cont::Algorithm::Copy(sortedBranches, tData.SortedBranchByVolume);
}
// Select the local top K branches by volume
@ -244,11 +238,11 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
// copy the top volume branches into a smaller array
// we skip index 0 because it must be the main branch (which has the highest volume)
vtkm::Id nActualSavedBranches =
std::min(nSavedBranches, this->SortedBranchByVolume.GetNumberOfValues() - 1);
std::min(nSavedBranches, tData.SortedBranchByVolume.GetNumberOfValues() - 1);
vtkm::worklet::contourtree_augmented::IdArrayType topVolumeBranch;
vtkm::cont::Algorithm::CopySubRange(
this->SortedBranchByVolume, 1, nActualSavedBranches, topVolumeBranch);
tData.SortedBranchByVolume, 1, nActualSavedBranches, topVolumeBranch);
auto branchRootByBranch = bdDataset.GetField("BranchRootByBranch")
.GetData()
@ -268,37 +262,37 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
vtkm::cont::Algorithm::Copy(branchRootByBranch, this->BranchRootByBranch);
vtkm::cont::Algorithm::Copy(branchRootGRId, this->BranchRootGRId);
vtkm::cont::Algorithm::Copy(branchRootByBranch, tData.BranchRootByBranch);
vtkm::cont::Algorithm::Copy(branchRootGRId, tData.BranchRootGRId);
// This seems weird, but we temporarily put the initialization of computing the branch decomposition tree here
this->IsParentBranch.AllocateAndFill(nBranches, false);
tData.IsParentBranch.AllocateAndFill(nBranches, false);
// we permute all branch information to align with the order by volume
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRootGRId, topVolumeBranch, this->TopVolumeBranchRootGRId);
branchRootGRId, topVolumeBranch, tData.TopVolumeBranchRootGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperEndGRId, topVolumeBranch, this->TopVolumeBranchUpperEndGRId);
upperEndGRId, topVolumeBranch, tData.TopVolumeBranchUpperEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerEndGRId, topVolumeBranch, this->TopVolumeBranchLowerEndGRId);
lowerEndGRId, topVolumeBranch, tData.TopVolumeBranchLowerEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchVolume, topVolumeBranch, this->TopVolumeBranchVolume);
tData.BranchVolume, topVolumeBranch, tData.TopVolumeBranchVolume);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchSaddleEpsilon, topVolumeBranch, this->TopVolumeBranchSaddleEpsilon);
tData.BranchSaddleEpsilon, topVolumeBranch, tData.TopVolumeBranchSaddleEpsilon);
auto resolveArray = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
InArrayHandleType topVolBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::PermuteArrayWithRawIndex<InArrayHandleType>(
inArray, topVolumeBranch, topVolBranchSaddleIsoValue);
this->TopVolumeBranchSaddleIsoValue = topVolBranchSaddleIsoValue;
tData.TopVolumeBranchSaddleIsoValue = topVolBranchSaddleIsoValue;
};
this->BranchSaddleIsoValue
tData.BranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}
@ -306,390 +300,7 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
void SelectTopVolumeContoursBlock::ComputeTopVolumeBranchHierarchy(
const vtkm::cont::DataSet& bdDataSet)
{
using vtkm::worklet::contourtree_augmented::IdArrayType;
vtkm::cont::Invoker invoke;
// we need upper/lower local ends and global ends for hierarchy of branches
auto upperLocalEndIds = bdDataSet.GetField("UpperEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto lowerLocalEndIds = bdDataSet.GetField("LowerEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto globalRegularIds = bdDataSet.GetField("RegularNodeGlobalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
IdArrayType upperEndGRIds =
bdDataSet.GetField("UpperEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
IdArrayType lowerEndGRIds =
bdDataSet.GetField("LowerEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
// let's check which top volume branches are known by the block
// We check the branchGRId of top volume branches to see whether there are matches within the block
const vtkm::Id nTopVolBranches = this->TopVolumeBranchLowerEndGRId.GetNumberOfValues();
// sortedBranchOrder: the branch order (in the ascending order of branch root)
// the high-level idea is to sort the branch root global regular ids
// and for each top-volume branch, we use binary search to get the original branch index
// if the top-volume branch does not exist in the block, it will be dropped out
IdArrayType sortedBranchGRId;
IdArrayType sortedBranchOrder;
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(this->BranchRootGRId.GetNumberOfValues()), sortedBranchOrder);
vtkm::cont::Algorithm::Copy(this->BranchRootGRId, sortedBranchGRId);
vtkm::cont::Algorithm::SortByKey(sortedBranchGRId, sortedBranchOrder);
this->TopVolBranchKnownByBlockStencil.Allocate(nTopVolBranches);
this->TopVolBranchGROrder.Allocate(nTopVolBranches);
// We reuse the IdxIfWithinBlockWorklet.
// This worklet searches for given values in a sorted array and returns the stencil & index if the value exists in the array.
// this->TopVolBranchGROrder: the order of the topVolBranch among all known branches if the branch is known by the block.
auto idxIfBranchWithinBlockWorklet =
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet();
invoke(idxIfBranchWithinBlockWorklet,
this->TopVolumeBranchRootGRId,
sortedBranchGRId,
this->TopVolBranchKnownByBlockStencil,
this->TopVolBranchGROrder);
// Dropping out top-volume branches that are not known by the block.
// the index of top-volume branches known by the block among all top-volume branches
IdArrayType topVolBranchKnownByBlockIndex;
vtkm::cont::ArrayHandleIndex topVolBranchesIndex(nTopVolBranches);
vtkm::cont::Algorithm::CopyIf(
topVolBranchesIndex, this->TopVolBranchKnownByBlockStencil, topVolBranchKnownByBlockIndex);
const vtkm::Id nTopVolBranchKnownByBlock = topVolBranchKnownByBlockIndex.GetNumberOfValues();
// filtered this->TopVolBranchGROrder, by removing NO_SUCH_ELEMENT
IdArrayType topVolBranchFilteredGROrder;
// this->TopVolBranchInfoActualIndex: the information index of the top-volume branch
vtkm::cont::Algorithm::CopyIf(
this->TopVolBranchGROrder, this->TopVolBranchKnownByBlockStencil, topVolBranchFilteredGROrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
sortedBranchOrder, topVolBranchFilteredGROrder, this->TopVolBranchInfoActualIndex);
// filtered branch saddle epsilons, global lower/upper end GR ids,
IdArrayType topVolFilteredBranchSaddleEpsilon;
IdArrayType topVolFilteredLowerEndGRId;
IdArrayType topVolFilteredUpperEndGRId;
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchSaddleEpsilon,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchUpperEndGRId,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredUpperEndGRId);
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchLowerEndGRId,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredLowerEndGRId);
// for each top-vol branch known by the block
// we get their upper end and lower end local ids
IdArrayType topVolBranchUpperLocalEnd;
IdArrayType topVolBranchLowerLocalEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, this->TopVolBranchInfoActualIndex, topVolBranchUpperLocalEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, this->TopVolBranchInfoActualIndex, topVolBranchLowerLocalEnd);
IdArrayType topVolLowerLocalEndGRId;
IdArrayType topVolUpperLocalEndGRId;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchLowerLocalEnd, topVolLowerLocalEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchUpperLocalEnd, topVolUpperLocalEndGRId);
// Below is the code to compute the branch hierarchy of top-volume branches
// We need this information because we not only want to visualize the contour
// on top-volume branches, but also on their parent branches.
// Because we use volume as the metric, the parent branch of a top-volume branch
// is either a top-volume branch or the root branch (where both ends are leaf nodes)
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchSaddleIsKnownWorklet
branchSaddleIsKnownWorklet;
// the branch saddle local ID if the saddle end is known by the block
IdArrayType branchSaddleIsKnown;
branchSaddleIsKnown.Allocate(nTopVolBranchKnownByBlock);
invoke(branchSaddleIsKnownWorklet, // worklet
topVolFilteredLowerEndGRId, // input
topVolBranchLowerLocalEnd, // input
topVolLowerLocalEndGRId, // input
topVolFilteredUpperEndGRId, // input
topVolBranchUpperLocalEnd, // input
topVolUpperLocalEndGRId, // input
topVolFilteredBranchSaddleEpsilon, // input
branchSaddleIsKnown); // output
// the order of top volume branches with parents known by the block
IdArrayType topVolChildBranch;
IdArrayType topVolChildBranchSaddle;
vtkm::cont::Algorithm::CopyIf(
topVolBranchKnownByBlockIndex,
branchSaddleIsKnown,
topVolChildBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
vtkm::cont::Algorithm::CopyIf(
branchSaddleIsKnown,
branchSaddleIsKnown,
topVolChildBranchSaddle,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
const vtkm::Id nChildBranch = topVolChildBranch.GetNumberOfValues();
// to compute the parent branch, we need to
// 1. for the branch saddle end, collect all superarcs involving it
// 2. get the branch information for selected superarcs
// 3. eliminate branch information for branches sharing the same saddle end
auto superarcs =
bdDataSet.GetField("Superarcs").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto branchRoots =
bdDataSet.GetField("BranchRoots").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
VTKM_ASSERT(superarcs.GetNumberOfValues() == branchRoots.GetNumberOfValues());
// we sort all superarcs by target to allow binary search
IdArrayType superarcsByTarget;
vtkm::worklet::scalar_topology::select_top_volume_contours::SuperarcTargetComparator
superarcComparator(superarcs);
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(superarcs.GetNumberOfValues()),
superarcsByTarget);
vtkm::cont::Algorithm::Sort(superarcsByTarget, superarcComparator);
IdArrayType permutedSuperarcs;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
superarcs, superarcsByTarget, permutedSuperarcs);
IdArrayType permutedBranchRoots;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, superarcsByTarget, permutedBranchRoots);
// the branch root of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleBranchRoot;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, topVolChildBranchSaddle, topVolChildBranchSaddleBranchRoot);
// the GR Ids of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleGRIds;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolChildBranchSaddle, topVolChildBranchSaddleGRIds);
// there is a debate to find all superarcs connect to a supernode
// strategy 1. iterate through saddles and parallelize over superarcs for search
// time complexity: O(nTopVolBranches)
// (nTopVolBranches usually <= 100, based on input parameter setting)
//
// strategy 2. parallelize over all saddles and use binary search to find superarcs
// time complexity: O(log_2(nSuperarcs)) (nSuperarcs can be considerably large)
//
// here, we choose strategy 2 for better extendability to high nTopVolBranches
// but in tests using nTopVolBranches <= 10, strategy 1 is generally faster
// note: after getting the branch root superarc, we use binary search to get the branch order
// because BranchRootByBranch is sorted by branch root (superarc) id
#ifdef DEBUG_PRINT
std::stringstream parentBranchStream;
parentBranchStream << "Debug for Parent Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nChildBranch, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Branch Saddle", topVolChildBranchSaddle, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle Root", topVolChildBranchSaddleBranchRoot, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle GR Id", topVolChildBranchSaddleGRIds, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintHeader(superarcs.GetNumberOfValues(),
parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Superarcs", permutedSuperarcs, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Branch roots", permutedBranchRoots, -1, parentBranchStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, parentBranchStream.str());
#endif // DEBUG_PRINT
// the corresponding parent branch of child branches
IdArrayType topVolChildBranchParent;
topVolChildBranchParent.AllocateAndFill(nChildBranch,
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
vtkm::worklet::scalar_topology::select_top_volume_contours::GetParentBranchWorklet
getParentBranchWorklet;
invoke(getParentBranchWorklet,
topVolChildBranchSaddle,
topVolChildBranchSaddleBranchRoot,
topVolChildBranchSaddleGRIds,
permutedSuperarcs,
permutedBranchRoots,
this->BranchRootByBranch,
upperEndGRIds,
lowerEndGRIds,
topVolChildBranchParent);
this->TopVolumeBranchParent.AllocateAndFill(
nTopVolBranches, vtkm::Id(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT));
vtkm::worklet::scalar_topology::select_top_volume_contours::AssignValueByIndex assignParentBranch;
// for each top volume branch, assign the parent branch info id in the block
invoke(
assignParentBranch, topVolChildBranch, topVolChildBranchParent, this->TopVolumeBranchParent);
// for each branch, assign true if it is a parent branch
invoke(assignParentBranch,
topVolChildBranchParent,
vtkm::cont::ArrayHandleConstant<bool>(true, nChildBranch),
this->IsParentBranch);
// sort all top-volume branches based on
// 1. parent branch info id: this->TopVolumeBranchParent
// 2. saddle-end value: this->TopVolumeBranchSaddleIsovalue
// 3. branch root global regular id (anything that can break tie)
auto resolveBranchParent = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchParentComparator<ValueType>
parentComparator(this->TopVolumeBranchParent, inArray, this->TopVolumeBranchRootGRId);
// sort index for all top volume branches
IdArrayType topVolSortForOuterSaddleIdx;
vtkm::cont::Algorithm::Copy(topVolBranchesIndex, topVolSortForOuterSaddleIdx);
vtkm::cont::Algorithm::Sort(topVolSortForOuterSaddleIdx, parentComparator);
IdArrayType parentPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->TopVolumeBranchParent, topVolSortForOuterSaddleIdx, parentPermutation);
// warning: when parent is NO_SUCH_ELEMENT, parentSaddleEps obtains 0
// However, the corresponding element will be discarded in collecting outer saddles
IdArrayType parentSaddleEpsPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchSaddleEpsilon, parentPermutation, parentSaddleEpsPermutation);
// Some branches have parent=NO_SUCH_ELEMENT (no parent)
// we collect the isovalue of the first and/or the last branches for each parent branch
// we collect the first if branchSaddleEpsilon(parent) < 0
// or the last if branchSaddleEpsilon(parent) > 0
// or both if branchSaddleEpsilon(parent) == 0
IdArrayType IsOuterSaddle;
IsOuterSaddle.Allocate(nTopVolBranches);
vtkm::worklet::scalar_topology::select_top_volume_contours::CollectOuterSaddle
collectOuterSaddleWorklet;
invoke(collectOuterSaddleWorklet, parentSaddleEpsPermutation, parentPermutation, IsOuterSaddle);
// after sorting by index back
// each top volume branch know whether it is the outer saddle of its parent
vtkm::cont::Algorithm::SortByKey(topVolSortForOuterSaddleIdx, IsOuterSaddle);
// collect branches that need contours on extra minima/maxima
// we store the information of the parent branches (on both directions)
IdArrayType extraMaximaParentBranch;
IdArrayType extraMinimaParentBranch;
IdArrayType extraMaximaParentBranchRootGRId;
IdArrayType extraMinimaParentBranchRootGRId;
IdArrayType allBranchGRIdByVolume;
IdArrayType branchGRIdByVolumeIdx;
// we need global branch order including the root branch
// this information should be consistent globally
allBranchGRIdByVolume.Allocate(nTopVolBranches + 1);
vtkm::cont::Algorithm::CopySubRange(
this->TopVolumeBranchRootGRId, 0, nTopVolBranches, allBranchGRIdByVolume, 1);
auto topBranchGRIdWritePortal = allBranchGRIdByVolume.WritePortal();
auto sortedBranchByVolPortal = this->SortedBranchByVolume.ReadPortal();
auto branchGRIdReadPortal = this->BranchRootGRId.ReadPortal();
topBranchGRIdWritePortal.Set(0, branchGRIdReadPortal.Get(sortedBranchByVolPortal.Get(0)));
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(allBranchGRIdByVolume.GetNumberOfValues()),
branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::SortByKey(allBranchGRIdByVolume, branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchParent,
IsOuterSaddle,
extraMaximaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchParent,
IsOuterSaddle,
extraMinimaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
if (extraMaximaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMaximaParentBranch, this->ExtraMaximaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMaximaParentBranch, this->ExtraMaximaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchRootGRId, extraMaximaParentBranch, extraMaximaParentBranchRootGRId);
InArrayHandleType extraMaximaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
IsOuterSaddle,
extraMaximaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
this->ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
// a worklet to binary search a number in a sorted array and return the index
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMaximaBranchOrder;
permutedExtraMaximaBranchOrder.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMaximaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMaximaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMaximaBranchOrder, this->ExtraMaximaBranchOrder);
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMinimaParentBranch, this->ExtraMinimaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMinimaParentBranch, this->ExtraMinimaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchRootGRId, extraMinimaParentBranch, extraMinimaParentBranchRootGRId);
InArrayHandleType extraMinimaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
IsOuterSaddle,
extraMinimaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
this->ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMinimaBranchOrder;
permutedExtraMinimaBranchOrder.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMinimaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMinimaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMinimaBranchOrder, this->ExtraMinimaBranchOrder);
}
};
this->TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveBranchParent);
this->bdtMaker.ComputeTopVolumeBranchHierarchy(bdDataSet, this->tData);
}
@ -701,7 +312,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
using vtkm::worklet::contourtree_augmented::IdArrayType;
// if no branch to extract from
if (this->TopVolumeBranchRootGRId.GetNumberOfValues() < 1)
if (tData.TopVolumeBranchRootGRId.GetNumberOfValues() < 1)
return;
// Let's create a mesh dataset to extract all the contours first
@ -711,7 +322,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
// usage: identifier of the branch
vtkm::cont::Algorithm::Copy(
bdDataSet.GetField("BranchRootGRId").GetData().AsArrayHandle<IdArrayType>(),
this->BranchRootGRId);
tData.BranchRootGRId);
// branch local upper end and lower end
// size: nBranches
@ -893,7 +504,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
IdArrayType topVolBranchWithinBlockId;
vtkm::cont::Algorithm::CopyIf(vtkm::cont::ArrayHandleIndex(nIsoValues),
this->TopVolBranchKnownByBlockStencil,
tData.TopVolBranchKnownByBlockStencil,
topVolBranchWithinBlockId);
auto topVolBranchWithinBlockIdPortal = topVolBranchWithinBlockId.ReadPortal();
@ -901,13 +512,13 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
// filtered branch saddle values
InArrayHandleType isoValues;
vtkm::cont::Algorithm::CopyIf(inArray, this->TopVolBranchKnownByBlockStencil, isoValues);
vtkm::cont::Algorithm::CopyIf(inArray, tData.TopVolBranchKnownByBlockStencil, isoValues);
auto isoValuePortal = isoValues.ReadPortal();
// filtered branch saddle epsilons
IdArrayType topVolBranchSaddleEpsilons;
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchSaddleEpsilon,
this->TopVolBranchKnownByBlockStencil,
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchSaddleEpsilon,
tData.TopVolBranchKnownByBlockStencil,
topVolBranchSaddleEpsilons);
auto topVolBranchSaddleEpsilonPortal = topVolBranchSaddleEpsilons.ReadPortal();
@ -917,11 +528,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
IdArrayType topVolLocalBranchLowerEnd;
vtkm::cont::ArrayHandle<bool> topVolIsParent;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperEndLocalIds, this->TopVolBranchInfoActualIndex, topVolLocalBranchUpperEnd);
upperEndLocalIds, tData.TopVolBranchInfoActualIndex, topVolLocalBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerEndLocalIds, this->TopVolBranchInfoActualIndex, topVolLocalBranchLowerEnd);
lowerEndLocalIds, tData.TopVolBranchInfoActualIndex, topVolLocalBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithRawIndex<vtkm::cont::ArrayHandle<bool>>(
this->IsParentBranch, this->TopVolBranchInfoActualIndex, topVolIsParent);
tData.IsParentBranch, tData.TopVolBranchInfoActualIndex, topVolIsParent);
auto topVolIsParentPortal = topVolIsParent.ReadPortal();
// we compute the superarc of the branch within the block
@ -948,7 +559,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
vtkm::worklet::contourtree_augmented::PrintHeader(sortedBranchGRId.GetNumberOfValues(),
branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Raw Branch GR", this->BranchRootGRId, -1, branchStream);
"Raw Branch GR", tData.BranchRootGRId, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Raw Upper End", upperLocalEndIds, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
@ -960,7 +571,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
vtkm::worklet::contourtree_augmented::PrintHeader(nIsoValues, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Top Branch GR", this->TopVolumeBranchRootGRId, -1, branchStream);
"Top Branch GR", tData.TopVolumeBranchRootGRId, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Top Branch Stencil", topVolBranchWithinBlockStencil, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
@ -975,8 +586,8 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
VTKM_LOG_S(vtkm::cont::LogLevel::Info, branchStream.str());
#endif
const vtkm::Id nExtraMaximaBranch = this->ExtraMaximaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMinimaBranch = this->ExtraMinimaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMaximaBranch = tData.ExtraMaximaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMinimaBranch = tData.ExtraMinimaBranchLowerEnd.GetNumberOfValues();
InArrayHandleType extraMaximaBranchIsoValue;
InArrayHandleType extraMinimaBranchIsoValue;
@ -988,11 +599,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
if (nExtraMaximaBranch)
{
extraMaximaBranchIsoValue =
this->ExtraMaximaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
tData.ExtraMaximaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
invoke(branchIsoSuperarcWorklet,
this->ExtraMaximaBranchUpperEnd,
this->ExtraMaximaBranchLowerEnd,
tData.ExtraMaximaBranchUpperEnd,
tData.ExtraMaximaBranchLowerEnd,
extraMaximaBranchIsoValue,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, nExtraMaximaBranch),
extraMaximaBranchSuperarcs,
@ -1003,15 +614,15 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
extraMaxStream << "Debug for Extra Maxima Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nExtraMaximaBranch, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Upper End", this->ExtraMaximaBranchUpperEnd, -1, extraMaxStream);
"Max Branch Upper End", tData.ExtraMaximaBranchUpperEnd, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Lower End", this->ExtraMaximaBranchLowerEnd, -1, extraMaxStream);
"Max Branch Lower End", tData.ExtraMaximaBranchLowerEnd, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"Max Branch IsoValue", extraMaximaBranchIsoValue, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Superarc", extraMaximaBranchSuperarcs, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Order", this->ExtraMaximaBranchOrder, -1, extraMaxStream);
"Max Branch Order", tData.ExtraMaximaBranchOrder, -1, extraMaxStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, extraMaxStream.str());
#endif // DEBUG_PRINT
}
@ -1019,11 +630,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
if (nExtraMinimaBranch)
{
extraMinimaBranchIsoValue =
this->ExtraMinimaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
tData.ExtraMinimaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
invoke(branchIsoSuperarcWorklet,
this->ExtraMinimaBranchUpperEnd,
this->ExtraMinimaBranchLowerEnd,
tData.ExtraMinimaBranchUpperEnd,
tData.ExtraMinimaBranchLowerEnd,
extraMinimaBranchIsoValue,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(-1, nExtraMinimaBranch),
extraMinimaBranchSuperarcs,
@ -1034,15 +645,15 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
extraMaxStream << "Debug for Extra Maxima Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nExtraMinimaBranch, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Upper End", this->ExtraMinimaBranchUpperEnd, -1, extraMinStream);
"Max Branch Upper End", tData.ExtraMinimaBranchUpperEnd, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Lower End", this->ExtraMinimaBranchLowerEnd, -1, extraMinStream);
"Max Branch Lower End", tData.ExtraMinimaBranchLowerEnd, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"Max Branch IsoValue", extraMinimaBranchIsoValue, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Superarc", extraMinimaBranchSuperarcs, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Order", this->ExtraMinimaBranchOrder, -1, extraMinStream);
"Max Branch Order", tData.ExtraMinimaBranchOrder, -1, extraMinStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, extraMinStream.str());
#endif // DEBUG_PRINT
}
@ -1051,8 +662,8 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
auto extraMinimaBranchSuperarcPortal = extraMinimaBranchSuperarcs.ReadPortal();
auto extraMaximaBranchIsoValuePortal = extraMaximaBranchIsoValue.ReadPortal();
auto extraMinimaBranchIsoValuePortal = extraMinimaBranchIsoValue.ReadPortal();
auto extraMaximaBranchOrderPortal = this->ExtraMaximaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = this->ExtraMinimaBranchOrder.ReadPortal();
auto extraMaximaBranchOrderPortal = tData.ExtraMaximaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = tData.ExtraMinimaBranchOrder.ReadPortal();
const vtkm::Id nContours = nTopVolBranchWithinBlock + nExtraMaximaBranch + nExtraMinimaBranch;
this->IsosurfaceEdgesOffset.AllocateAndFill(nContours, 0);
@ -1295,7 +906,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
<< " " << std::setw(60) << std::left
<< "Number of Meshes On Branches: " << nMeshesOnBranches << std::endl);
};
this->TopVolumeBranchSaddleIsoValue
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}

@ -55,6 +55,8 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/TopVolumeBranchData.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/BranchDecompositionTreeMaker.h>
namespace vtkm
{
@ -69,65 +71,54 @@ struct SelectTopVolumeContoursBlock
{
SelectTopVolumeContoursBlock(vtkm::Id localBlockNo, int globalBlockId);
void SortBranchByVolume(const vtkm::cont::DataSet& bdDataSet, const vtkm::Id totalVolume);
void SelectLocalTopVolumeBranch(const vtkm::cont::DataSet& bdDataSet,
const vtkm::Id nSavedBranches);
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet);
void ExtractIsosurfaceOnSelectedBranch(const vtkm::cont::DataSet& bdDataSet,
const bool isMarchingCubes,
const vtkm::cont::LogLevel timingsLogLevel);
// Block metadata
vtkm::Id LocalBlockNo;
int GlobalBlockId; // TODO/FIXME: Check whether really needed. Possibly only during debugging
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
vtkm::cont::ArrayHandle<bool> IsParentBranch;
vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
TopVolumeBranchData tData;
// Output Datasets.
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
// the factory class to compute the relation of top-volume branches
BranchDecompositionTreeMaker bdtMaker;
// Other top-volume branch information
// whether the top volume branch is known by the block
// size: nTopVolBranches
// value range: [0, 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
// the branch order (among all branches) by branch root global regular ids
// size: nTopVolBranches
// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
// the branch information index (known by the block) of the top volume branch
// size: nTopVolBranchKnownByBlock
// value range: [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
// information to extract extra isosurface for extrema
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
//vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
//vtkm::cont::ArrayHandle<bool> IsParentBranch;
//vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
//// Output Datasets.
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
//// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
//vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
//// Other top-volume branch information
//// whether the top volume branch is known by the block
//// size: nTopVolBranches
//// value range: [0, 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
//// the branch order (among all branches) by branch root global regular ids
//// size: nTopVolBranches
//// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
//// the branch information index (known by the block) of the top volume branch
//// size: nTopVolBranchKnownByBlock
//// value range: [0, nBranches - 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
//// information to extract extra isosurface for extrema
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
//vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
//vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
// Isosurface output
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> IsosurfaceEdgesFrom;
@ -139,6 +130,17 @@ struct SelectTopVolumeContoursBlock
// Destroy function allowing DIY to own blocks and clean them up after use
static void Destroy(void* b) { delete static_cast<SelectTopVolumeContoursBlock*>(b); }
void SortBranchByVolume(const vtkm::cont::DataSet& bdDataSet, const vtkm::Id totalVolume);
void SelectLocalTopVolumeBranch(const vtkm::cont::DataSet& bdDataSet,
const vtkm::Id nSavedBranches);
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet);
void ExtractIsosurfaceOnSelectedBranch(const vtkm::cont::DataSet& bdDataSet,
const bool isMarchingCubes,
const vtkm::cont::LogLevel timingsLogLevel);
};
} // namespace internal

@ -101,11 +101,11 @@ void SelectTopVolumeContoursFunctor::operator()(
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Block " << b->GlobalBlockId << " enqueue to Block " << target.gid);
#endif
auto topVolBranchRootGRIdPortal = b->TopVolumeBranchRootGRId.ReadPortal();
auto topVolBranchVolumePortal = b->TopVolumeBranchVolume.ReadPortal();
auto topVolBranchSaddleEpsilonPortal = b->TopVolumeBranchSaddleEpsilon.ReadPortal();
auto topVolBranchUpperEndPortal = b->TopVolumeBranchUpperEndGRId.ReadPortal();
auto topVolBranchLowerEndPortal = b->TopVolumeBranchLowerEndGRId.ReadPortal();
auto topVolBranchRootGRIdPortal = b->tData.TopVolumeBranchRootGRId.ReadPortal();
auto topVolBranchVolumePortal = b->tData.TopVolumeBranchVolume.ReadPortal();
auto topVolBranchSaddleEpsilonPortal = b->tData.TopVolumeBranchSaddleEpsilon.ReadPortal();
auto topVolBranchUpperEndPortal = b->tData.TopVolumeBranchUpperEndGRId.ReadPortal();
auto topVolBranchLowerEndPortal = b->tData.TopVolumeBranchLowerEndGRId.ReadPortal();
vtkm::Id nBranches = topVolBranchRootGRIdPortal.GetNumberOfValues();
@ -128,11 +128,11 @@ void SelectTopVolumeContoursFunctor::operator()(
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
rp.enqueue<ValueType>(target, topVolBranchSaddleIsoValuePortal.Get(branch));
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
// rp.enqueue(target, b->TopVolumeBranchRootGRId);
// rp.enqueue(target, b->TopVolumeBranchVolume);
// rp.enqueue(target, b->tData.TopVolumeBranchRootGRId);
// rp.enqueue(target, b->tData.TopVolumeBranchVolume);
}
}
}
@ -267,7 +267,7 @@ void SelectTopVolumeContoursFunctor::operator()(
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue<InArrayHandleType>(ingid, incomingTopVolBranchSaddleIsoValue);
vtkm::Id nSelf = b->TopVolumeBranchRootGRId.GetNumberOfValues();
vtkm::Id nSelf = b->tData.TopVolumeBranchRootGRId.GetNumberOfValues();
#ifdef DEBUG_PRINT_COMBINED_HIGH_VOLUME_BRANCH
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
@ -288,15 +288,15 @@ void SelectTopVolumeContoursFunctor::operator()(
vtkm::worklet::contourtree_augmented::PrintHeader(nSelf, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchId", b->TopVolumeBranchRootGRId, -1, rs);
"selfTopBranchId", b->tData.TopVolumeBranchRootGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchVol", b->TopVolumeBranchVolume, -1, rs);
"selfTopBranchVol", b->tData.TopVolumeBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfTopSaddleVal", inArray, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchUpperEnd", b->TopVolumeBranchUpperEndGRId, -1, rs);
"selfTopBranchUpperEnd", b->tData.TopVolumeBranchUpperEndGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchLowerEnd", b->TopVolumeBranchLowerEndGRId, -1, rs);
"selfTopBranchLowerEnd", b->tData.TopVolumeBranchLowerEndGRId, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
@ -327,15 +327,15 @@ void SelectTopVolumeContoursFunctor::operator()(
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
incomingTopVolBranchSaddleIsoValue, 0, nIncoming, mergedTopVolBranchSaddleIsoValue, 0);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchRootGRId, 0, nSelf, mergedTopVolBranchGRId, nIncoming);
b->tData.TopVolumeBranchRootGRId, 0, nSelf, mergedTopVolBranchGRId, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchVolume, 0, nSelf, mergedTopVolBranchVolume, nIncoming);
b->tData.TopVolumeBranchVolume, 0, nSelf, mergedTopVolBranchVolume, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchSaddleEpsilon, 0, nSelf, mergedTopVolBranchSaddleEpsilon, nIncoming);
b->tData.TopVolumeBranchSaddleEpsilon, 0, nSelf, mergedTopVolBranchSaddleEpsilon, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchUpperEndGRId, 0, nSelf, mergedTopVolBranchUpperEnd, nIncoming);
b->tData.TopVolumeBranchUpperEndGRId, 0, nSelf, mergedTopVolBranchUpperEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchLowerEndGRId, 0, nSelf, mergedTopVolBranchLowerEnd, nIncoming);
b->tData.TopVolumeBranchLowerEndGRId, 0, nSelf, mergedTopVolBranchLowerEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
inArray, 0, nSelf, mergedTopVolBranchSaddleIsoValue, nIncoming);
@ -439,17 +439,17 @@ void SelectTopVolumeContoursFunctor::operator()(
if (nMergedUnique > this->nSavedBranches)
{
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchGRId, 0, this->nSavedBranches, b->TopVolumeBranchRootGRId);
mergedUniqueBranchGRId, 0, this->nSavedBranches, b->tData.TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchVolume, 0, this->nSavedBranches, b->TopVolumeBranchVolume);
mergedUniqueBranchVolume, 0, this->nSavedBranches, b->tData.TopVolumeBranchVolume);
vtkm::cont::Algorithm::CopySubRange(mergedUniqueBranchSaddleEpsilon,
0,
this->nSavedBranches,
b->TopVolumeBranchSaddleEpsilon);
b->tData.TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchUpperEnd, 0, this->nSavedBranches, b->TopVolumeBranchUpperEndGRId);
mergedUniqueBranchUpperEnd, 0, this->nSavedBranches, b->tData.TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchLowerEnd, 0, this->nSavedBranches, b->TopVolumeBranchLowerEndGRId);
mergedUniqueBranchLowerEnd, 0, this->nSavedBranches, b->tData.TopVolumeBranchLowerEndGRId);
// InArrayHandleType subRangeUniqueBranchSaddleIsoValue;
inArray.Allocate(this->nSavedBranches);
vtkm::cont::Algorithm::CopySubRange(
@ -458,17 +458,17 @@ void SelectTopVolumeContoursFunctor::operator()(
}
else
{
vtkm::cont::Algorithm::Copy(mergedUniqueBranchGRId, b->TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchVolume, b->TopVolumeBranchVolume);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchGRId, b->tData.TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchVolume, b->tData.TopVolumeBranchVolume);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleEpsilon,
b->TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchUpperEnd, b->TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchLowerEnd, b->TopVolumeBranchLowerEndGRId);
b->tData.TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchUpperEnd, b->tData.TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchLowerEnd, b->tData.TopVolumeBranchLowerEndGRId);
inArray.Allocate(nMergedUnique);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleIsoValue, inArray);
}
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}
}

@ -0,0 +1,527 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=======================================================================================
//
// Parallel Peak Pruning v. 2.0
//
// Started June 15, 2017
//
// Copyright Hamish Carr, University of Leeds
//
// BranchDecompositionTreeMaker.h
//
//=======================================================================================
//
// COMMENTS:
//
// This class computes the branch decomposition tree of top-volume branches
//
//=======================================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_BranchDecompositionTreeMaker_h
#define vtk_m_filter_scalar_topology_worklet_BranchDecompositionTreeMaker_h
#ifdef DEBUG_PRINT
#define DEBUG_BRANCH_DECOMPOSITION_TREE_MAKER
#endif
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/TopVolumeBranchData.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ArrayTransforms.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/BranchParentComparator.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/ClarifyBranchEndSupernodeTypeWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/GetBranchHierarchyWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/GetBranchVolumeWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/LocalIsosurfaceExtractWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/Predicates.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/UpdateInfoByBranchDirectionWorklet.h>
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
/// Facture class for augmenting the hierarchical contour tree to enable computations of measures, e.g., volumne
class BranchDecompositionTreeMaker
{ // class BranchDecompositionTreeMaker
public:
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet,
TopVolumeBranchData& tData);
private:
/// Used internally to Invoke worklets
vtkm::cont::Invoker invoke;
}; // class BranchDecompositionTreeMaker
/// <summary>
/// Pipeline to compute the hierarchy of top branches by volume
/// </summary>
inline void BranchDecompositionTreeMaker::ComputeTopVolumeBranchHierarchy(
const vtkm::cont::DataSet& bdDataSet,
TopVolumeBranchData& tData)
{
using vtkm::worklet::contourtree_augmented::IdArrayType;
// we need upper/lower local ends and global ends for hierarchy of branches
auto upperLocalEndIds = bdDataSet.GetField("UpperEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto lowerLocalEndIds = bdDataSet.GetField("LowerEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto globalRegularIds = bdDataSet.GetField("RegularNodeGlobalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
IdArrayType upperEndGRIds =
bdDataSet.GetField("UpperEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
IdArrayType lowerEndGRIds =
bdDataSet.GetField("LowerEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
// let's check which top volume branches are known by the block
// We check the branchGRId of top volume branches to see whether there are matches within the block
const vtkm::Id nTopVolBranches = tData.TopVolumeBranchLowerEndGRId.GetNumberOfValues();
// sortedBranchOrder: the branch order (in the ascending order of branch root)
// the high-level idea is to sort the branch root global regular ids
// and for each top-volume branch, we use binary search to get the original branch index
// if the top-volume branch does not exist in the block, it will be dropped out
IdArrayType sortedBranchGRId;
IdArrayType sortedBranchOrder;
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(tData.BranchRootGRId.GetNumberOfValues()), sortedBranchOrder);
vtkm::cont::Algorithm::Copy(tData.BranchRootGRId, sortedBranchGRId);
vtkm::cont::Algorithm::SortByKey(sortedBranchGRId, sortedBranchOrder);
tData.TopVolBranchKnownByBlockStencil.Allocate(nTopVolBranches);
tData.TopVolBranchGROrder.Allocate(nTopVolBranches);
// We reuse the IdxIfWithinBlockWorklet.
// This worklet searches for given values in a sorted array and returns the stencil & index if the value exists in the array.
// tData.TopVolBranchGROrder: the order of the topVolBranch among all known branches if the branch is known by the block.
auto idxIfBranchWithinBlockWorklet =
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet();
invoke(idxIfBranchWithinBlockWorklet,
tData.TopVolumeBranchRootGRId,
sortedBranchGRId,
tData.TopVolBranchKnownByBlockStencil,
tData.TopVolBranchGROrder);
// Dropping out top-volume branches that are not known by the block.
// the index of top-volume branches known by the block among all top-volume branches
IdArrayType topVolBranchKnownByBlockIndex;
vtkm::cont::ArrayHandleIndex topVolBranchesIndex(nTopVolBranches);
vtkm::cont::Algorithm::CopyIf(
topVolBranchesIndex, tData.TopVolBranchKnownByBlockStencil, topVolBranchKnownByBlockIndex);
const vtkm::Id nTopVolBranchKnownByBlock = topVolBranchKnownByBlockIndex.GetNumberOfValues();
// filtered tData.TopVolBranchGROrder, by removing NO_SUCH_ELEMENT
IdArrayType topVolBranchFilteredGROrder;
// tData.TopVolBranchInfoActualIndex: the information index of the top-volume branch
vtkm::cont::Algorithm::CopyIf(
tData.TopVolBranchGROrder, tData.TopVolBranchKnownByBlockStencil, topVolBranchFilteredGROrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
sortedBranchOrder, topVolBranchFilteredGROrder, tData.TopVolBranchInfoActualIndex);
// filtered branch saddle epsilons, global lower/upper end GR ids,
IdArrayType topVolFilteredBranchSaddleEpsilon;
IdArrayType topVolFilteredLowerEndGRId;
IdArrayType topVolFilteredUpperEndGRId;
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchSaddleEpsilon,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchUpperEndGRId,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredUpperEndGRId);
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchLowerEndGRId,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredLowerEndGRId);
// for each top-vol branch known by the block
// we get their upper end and lower end local ids
IdArrayType topVolBranchUpperLocalEnd;
IdArrayType topVolBranchLowerLocalEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, tData.TopVolBranchInfoActualIndex, topVolBranchUpperLocalEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, tData.TopVolBranchInfoActualIndex, topVolBranchLowerLocalEnd);
IdArrayType topVolLowerLocalEndGRId;
IdArrayType topVolUpperLocalEndGRId;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchLowerLocalEnd, topVolLowerLocalEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchUpperLocalEnd, topVolUpperLocalEndGRId);
// Below is the code to compute the branch hierarchy of top-volume branches
// We need this information because we not only want to visualize the contour
// on top-volume branches, but also on their parent branches.
// Because we use volume as the metric, the parent branch of a top-volume branch
// is either a top-volume branch or the root branch (where both ends are leaf nodes)
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchSaddleIsKnownWorklet
branchSaddleIsKnownWorklet;
// the branch saddle local ID if the saddle end is known by the block
IdArrayType branchSaddleIsKnown;
branchSaddleIsKnown.Allocate(nTopVolBranchKnownByBlock);
invoke(branchSaddleIsKnownWorklet, // worklet
topVolFilteredLowerEndGRId, // input
topVolBranchLowerLocalEnd, // input
topVolLowerLocalEndGRId, // input
topVolFilteredUpperEndGRId, // input
topVolBranchUpperLocalEnd, // input
topVolUpperLocalEndGRId, // input
topVolFilteredBranchSaddleEpsilon, // input
branchSaddleIsKnown); // output
// the order of top volume branches with parents known by the block
IdArrayType topVolChildBranch;
IdArrayType topVolChildBranchSaddle;
vtkm::cont::Algorithm::CopyIf(
topVolBranchKnownByBlockIndex,
branchSaddleIsKnown,
topVolChildBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
vtkm::cont::Algorithm::CopyIf(
branchSaddleIsKnown,
branchSaddleIsKnown,
topVolChildBranchSaddle,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
const vtkm::Id nChildBranch = topVolChildBranch.GetNumberOfValues();
// to compute the parent branch, we need to
// 1. for the branch saddle end, collect all superarcs involving it
// 2. get the branch information for selected superarcs
// 3. eliminate branch information for branches sharing the same saddle end
auto superarcs =
bdDataSet.GetField("Superarcs").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto branchRoots =
bdDataSet.GetField("BranchRoots").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
VTKM_ASSERT(superarcs.GetNumberOfValues() == branchRoots.GetNumberOfValues());
// we sort all superarcs by target to allow binary search
IdArrayType superarcsByTarget;
vtkm::worklet::scalar_topology::select_top_volume_contours::SuperarcTargetComparator
superarcComparator(superarcs);
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(superarcs.GetNumberOfValues()),
superarcsByTarget);
vtkm::cont::Algorithm::Sort(superarcsByTarget, superarcComparator);
IdArrayType permutedSuperarcs;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
superarcs, superarcsByTarget, permutedSuperarcs);
IdArrayType permutedBranchRoots;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, superarcsByTarget, permutedBranchRoots);
// the branch root of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleBranchRoot;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, topVolChildBranchSaddle, topVolChildBranchSaddleBranchRoot);
// the GR Ids of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleGRIds;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolChildBranchSaddle, topVolChildBranchSaddleGRIds);
// there is a debate to find all superarcs connect to a supernode
// strategy 1. iterate through saddles and parallelize over superarcs for search
// time complexity: O(nTopVolBranches)
// (nTopVolBranches usually <= 100, based on input parameter setting)
//
// strategy 2. parallelize over all saddles and use binary search to find superarcs
// time complexity: O(log_2(nSuperarcs)) (nSuperarcs can be considerably large)
//
// here, we choose strategy 2 for better extendability to high nTopVolBranches
// but in tests using nTopVolBranches <= 10, strategy 1 is generally faster
// note: after getting the branch root superarc, we use binary search to get the branch order
// because BranchRootByBranch is sorted by branch root (superarc) id
#ifdef DEBUG_PRINT
std::stringstream parentBranchStream;
vtkm::worklet::contourtree_augmented::PrintHeader(nChildBranch, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Branch Saddle", topVolChildBranchSaddle, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle Root", topVolChildBranchSaddleBranchRoot, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle GR Id", topVolChildBranchSaddleGRIds, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintHeader(superarcs.GetNumberOfValues(),
parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Superarcs", permutedSuperarcs, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Branch roots", permutedBranchRoots, -1, parentBranchStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, parentBranchStream.str());
#endif // DEBUG_PRINT
// the corresponding parent branch of child branches
IdArrayType topVolChildBranchParent;
topVolChildBranchParent.AllocateAndFill(nChildBranch,
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
vtkm::worklet::scalar_topology::select_top_volume_contours::GetParentBranchWorklet
getParentBranchWorklet;
invoke(getParentBranchWorklet,
topVolChildBranchSaddle,
topVolChildBranchSaddleBranchRoot,
topVolChildBranchSaddleGRIds,
permutedSuperarcs,
permutedBranchRoots,
tData.BranchRootByBranch,
upperEndGRIds,
lowerEndGRIds,
topVolChildBranchParent);
tData.TopVolumeBranchParent.AllocateAndFill(
nTopVolBranches, vtkm::Id(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT));
vtkm::worklet::scalar_topology::select_top_volume_contours::AssignValueByIndex assignParentBranch;
// for each top volume branch, assign the parent branch info id in the block
invoke(
assignParentBranch, topVolChildBranch, topVolChildBranchParent, tData.TopVolumeBranchParent);
// for each branch, assign true if it is a parent branch
invoke(assignParentBranch,
topVolChildBranchParent,
vtkm::cont::ArrayHandleConstant<bool>(true, nChildBranch),
tData.IsParentBranch);
// sort all top-volume branches based on
// 1. parent branch info id: tData.TopVolumeBranchParent
// 2. saddle-end value: tData.TopVolumeBranchSaddleIsovalue
// 3. branch root global regular id (anything that can break tie)
IdArrayType topVolSortForOuterSaddleIdx;
vtkm::cont::Algorithm::Copy(topVolBranchesIndex, topVolSortForOuterSaddleIdx);
auto resolveBranchParentSorter = [&](const auto& inArray)
{
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchParentComparator<ValueType>
parentComparator(tData.TopVolumeBranchParent, inArray, tData.TopVolumeBranchRootGRId);
// sort index for all top volume branches
vtkm::cont::Algorithm::Sort(topVolSortForOuterSaddleIdx, parentComparator);
};
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveBranchParentSorter);
IdArrayType parentPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.TopVolumeBranchParent, topVolSortForOuterSaddleIdx, parentPermutation);
// warning: when parent is NO_SUCH_ELEMENT, parentSaddleEps obtains 0
// However, the corresponding element will be discarded in collecting outer saddles
IdArrayType parentSaddleEpsPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchSaddleEpsilon, parentPermutation, parentSaddleEpsPermutation);
// Some branches have parent=NO_SUCH_ELEMENT (no parent)
// we collect the isovalue of the first and/or the last branches for each parent branch
// we collect the first if branchSaddleEpsilon(parent) < 0
// or the last if branchSaddleEpsilon(parent) > 0
// or both if branchSaddleEpsilon(parent) == 0
IdArrayType IsOuterSaddle;
IsOuterSaddle.Allocate(nTopVolBranches);
vtkm::worklet::scalar_topology::select_top_volume_contours::CollectOuterSaddle
collectOuterSaddleWorklet;
invoke(collectOuterSaddleWorklet, parentSaddleEpsPermutation, parentPermutation, IsOuterSaddle);
// after sorting by index back
// each top volume branch know whether it is the outer saddle of its parent
vtkm::cont::Algorithm::SortByKey(topVolSortForOuterSaddleIdx, IsOuterSaddle);
// collect branches that need contours on extra minima/maxima
// we store the information of the parent branches (on both directions)
IdArrayType extraMaximaParentBranch;
IdArrayType extraMinimaParentBranch;
IdArrayType extraMaximaParentBranchRootGRId;
IdArrayType extraMinimaParentBranchRootGRId;
IdArrayType allBranchGRIdByVolume;
IdArrayType branchGRIdByVolumeIdx;
// we need global branch order including the root branch
// this information should be consistent globally
allBranchGRIdByVolume.Allocate(nTopVolBranches + 1);
vtkm::cont::Algorithm::CopySubRange(
tData.TopVolumeBranchRootGRId, 0, nTopVolBranches, allBranchGRIdByVolume, 1);
auto topBranchGRIdWritePortal = allBranchGRIdByVolume.WritePortal();
auto sortedBranchByVolPortal = tData.SortedBranchByVolume.ReadPortal();
auto branchGRIdReadPortal = tData.BranchRootGRId.ReadPortal();
topBranchGRIdWritePortal.Set(0, branchGRIdReadPortal.Get(sortedBranchByVolPortal.Get(0)));
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(allBranchGRIdByVolume.GetNumberOfValues()),
branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::SortByKey(allBranchGRIdByVolume, branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::CopyIf(
tData.TopVolumeBranchParent,
IsOuterSaddle,
extraMaximaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
vtkm::cont::Algorithm::CopyIf(
tData.TopVolumeBranchParent,
IsOuterSaddle,
extraMinimaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
if (extraMaximaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMaximaParentBranch, tData.ExtraMaximaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMaximaParentBranch, tData.ExtraMaximaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchRootGRId, extraMaximaParentBranch, extraMaximaParentBranchRootGRId);
//InArrayHandleType extraMaximaBranchIsoValue;
//vtkm::cont::Algorithm::CopyIf(
// tData.TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
// IsOuterSaddle,
// extraMaximaBranchIsoValue,
// vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
//tData.ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
// a worklet to binary search a number in a sorted array and return the index
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMaximaBranchOrder;
permutedExtraMaximaBranchOrder.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMaximaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMaximaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMaximaBranchOrder, tData.ExtraMaximaBranchOrder);
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMinimaParentBranch, tData.ExtraMinimaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMinimaParentBranch, tData.ExtraMinimaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchRootGRId, extraMinimaParentBranch, extraMinimaParentBranchRootGRId);
//InArrayHandleType extraMinimaBranchIsoValue;
//vtkm::cont::Algorithm::CopyIf(
// tData.TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
// IsOuterSaddle,
// extraMinimaBranchIsoValue,
// vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
//tData.ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMinimaBranchOrder;
permutedExtraMinimaBranchOrder.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMinimaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMinimaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMinimaBranchOrder, tData.ExtraMinimaBranchOrder);
}
auto resolveExtraContourSaddleValue = [&](const auto& inArray)
{
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
if (extraMaximaParentBranch.GetNumberOfValues())
{
InArrayHandleType extraMaximaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
inArray,
IsOuterSaddle,
extraMaximaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
tData.ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
InArrayHandleType extraMinimaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
inArray,
IsOuterSaddle,
extraMinimaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
tData.ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
}
};
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveExtraContourSaddleValue);
}
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif

@ -10,6 +10,7 @@
set(headers
Predicates.h
TopVolumeBranchData.h
ClarifyBranchEndSupernodeTypeWorklet.h
UpdateInfoByBranchDirectionWorklet.h
GetBranchHierarchyWorklet.h
@ -18,6 +19,7 @@ set(headers
BranchVolumeComparator.h
MarchingCubesDataTables.h
LocalIsosurfaceExtractWorklet.h
BranchDecompositionTreeMaker.h
)
#-----------------------------------------------------------------------------

@ -0,0 +1,131 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=======================================================================================
//
// Parallel Peak Pruning v. 2.0
//
// Started June 15, 2017
//
// Copyright Hamish Carr, University of Leeds
//
// BranchDecompositionTreeMaker.h
//
//=======================================================================================
//
// COMMENTS:
//
// This class computes the branch decomposition tree of top-volume branches
//
//=======================================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_TopVolumeBranchData_h
#define vtk_m_filter_scalar_topology_worklet_TopVolumeBranchData_h
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#ifdef DEBUG_PRINT
#define DEBUG_BRANCH_DECOMPOSITION_TREE_MAKER
#endif
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
/// Data to store all information about top branches by volume
struct TopVolumeBranchData
{ // struct TopVolumeBranchData
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
vtkm::cont::ArrayHandle<bool> IsParentBranch;
vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
// Output Datasets.
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
// Other top-volume branch information
// whether the top volume branch is known by the block
// size: nTopVolBranches
// value range: [0, 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
// the branch order (among all branches) by branch root global regular ids
// size: nTopVolBranches
// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
// the branch information index (known by the block) of the top volume branch
// size: nTopVolBranchKnownByBlock
// value range: [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
// information to extract extra isosurface for extrema
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
}; // class TopVolumeBranchData
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif