mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
Merge branch 'master' into standard_normal
This commit is contained in:
commit
980c4864ac
@ -1,125 +0,0 @@
|
||||
|
||||
|
||||
.slurm_p9_cuda: &slurm_p9_cuda
|
||||
tags:
|
||||
- nmc
|
||||
- slurm
|
||||
- nmc-xxfe1-sched-001
|
||||
- xx-fe1
|
||||
variables:
|
||||
NMC_FE1_SLURM_PARAMETERS: " -N1 -p ecp-p9-4v100 --extra-node-info=*:*:* -t 1:30:00 "
|
||||
CC: "gcc"
|
||||
CXX: "g++"
|
||||
CUDAHOSTCXX: "g++"
|
||||
before_script:
|
||||
# We need gcc-4.8.5, which is the system default compiler but not a compiler
|
||||
# listed under the module system.
|
||||
#
|
||||
# That means to get this to work properly we explicitly do not request
|
||||
# any compiler.
|
||||
- module load cuda cmake/3.14.5
|
||||
|
||||
|
||||
.slurm_p9_opemp: &slurm_p9_opemp
|
||||
tags:
|
||||
- nmc
|
||||
- slurm
|
||||
- nmc-xxfe1-sched-001
|
||||
- xx-fe1
|
||||
variables:
|
||||
NMC_FE1_SLURM_PARAMETERS: " -N1 -p ecp-p9-4v100 --extra-node-info=*:*:* -t 1:30:00 "
|
||||
before_script:
|
||||
- module load gcc/8.3.0 openmpi/3.1.4 cmake/3.14.5
|
||||
|
||||
.cmake_build_artifacts: &cmake_build_artifacts
|
||||
artifacts:
|
||||
expire_in: 24 hours
|
||||
when: always
|
||||
paths:
|
||||
# The artifacts of the build.
|
||||
- vtkm-build/bin/
|
||||
- vtkm-build/include/
|
||||
|
||||
# CTest files.
|
||||
# XXX(globbing): Can be simplified with support from
|
||||
# https://gitlab.com/gitlab-org/gitlab-runner/issues/4840
|
||||
- vtkm-build/CTestCustom*.cmake
|
||||
- vtkm-build/CTestTestfile.cmake
|
||||
- vtkm-build/*/CTestTestfile.cmake
|
||||
- vtkm-build/*/*/CTestTestfile.cmake
|
||||
- vtkm-build/*/*/*/CTestTestfile.cmake
|
||||
- vtkm-build/*/*/*/*/CTestTestfile.cmake
|
||||
- vtkm-build/*/*/*/*/*/CTestTestfile.cmake
|
||||
- vtkm-build/Testing/
|
||||
|
||||
# CDash files.
|
||||
- vtkm-build/DartConfiguration.tcl
|
||||
|
||||
.cmake_build_p9_cuda: &cmake_build_p9_cuda
|
||||
stage: build
|
||||
script:
|
||||
- srun env | grep SLURM_JOB_NAME
|
||||
- mkdir vtkm-build
|
||||
- pushd vtkm-build
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DVTKm_ENABLE_CUDA=ON -S ../
|
||||
- cmake --build . -j20
|
||||
- popd
|
||||
|
||||
.cmake_build_p9_openmp: &cmake_build_p9_openmp
|
||||
stage: build
|
||||
script:
|
||||
- srun env | grep SLURM_JOB_NAME
|
||||
- mkdir vtkm-build
|
||||
- pushd vtkm-build
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DVTKm_ENABLE_OPENMP=ON -S ../
|
||||
- cmake --build . -j20
|
||||
- popd
|
||||
|
||||
|
||||
|
||||
.cmake_test_p9: &cmake_test_p9
|
||||
stage: test
|
||||
script:
|
||||
- echo "running the test using artifacts of the build"
|
||||
- pushd vtkm-build
|
||||
# We need to exclude the following tests
|
||||
# - CopyrightStatement
|
||||
# - TestInstallSetup
|
||||
# - SourceInInstall
|
||||
# Which we can do by using an exclude regex
|
||||
- ctest -E "Install|CopyrightStatement"
|
||||
- popd
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
build:p9_openmp:
|
||||
extends:
|
||||
- .slurm_p9_opemp
|
||||
- .cmake_build_artifacts
|
||||
- .cmake_build_p9_openmp
|
||||
|
||||
test:p9_openmp:
|
||||
extends:
|
||||
- .slurm_p9_opemp
|
||||
- .cmake_test_p9
|
||||
dependencies:
|
||||
- build:p9_openmp
|
||||
needs:
|
||||
- build:p9_openmp
|
||||
|
||||
build:p9_cuda:
|
||||
extends:
|
||||
- .slurm_p9_cuda
|
||||
- .cmake_build_artifacts
|
||||
- .cmake_build_p9_cuda
|
||||
|
||||
test:p9_cuda:
|
||||
extends:
|
||||
- .slurm_p9_cuda
|
||||
- .cmake_test_p9
|
||||
dependencies:
|
||||
- build:p9_cuda
|
||||
needs:
|
||||
- build:p9_cuda
|
23
CMake/VTKmCMakeBackports.cmake
Normal file
23
CMake/VTKmCMakeBackports.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
##============================================================================
|
||||
## 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.
|
||||
##============================================================================
|
||||
|
||||
file(GLOB cmake_version_backports
|
||||
LIST_DIRECTORIES true
|
||||
RELATIVE "${CMAKE_CURRENT_LIST_DIR}/patches"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/patches/*")
|
||||
|
||||
foreach (cmake_version_backport IN LISTS cmake_version_backports)
|
||||
if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/patches/${cmake_version_backport}")
|
||||
continue ()
|
||||
endif ()
|
||||
if (CMAKE_VERSION VERSION_LESS "${cmake_version_backport}")
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}/patches/${cmake_version_backport}")
|
||||
endif ()
|
||||
endforeach ()
|
@ -1,24 +0,0 @@
|
||||
##============================================================================
|
||||
## Copyright (c) Kitware, Inc.
|
||||
## All rights reserved.
|
||||
## See LICENSE.txt for details.
|
||||
##
|
||||
## This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
## PURPOSE. See the above copyright notice for more information.
|
||||
##============================================================================
|
||||
|
||||
if(VTKm_ENABLE_MPI AND NOT TARGET MPI::MPI_CXX)
|
||||
if(CMAKE_VERSION VERSION_LESS 3.15)
|
||||
#While CMake 3.10 introduced the new MPI module.
|
||||
#Fixes related to MPI+CUDA that VTK-m needs are
|
||||
#only found in CMake 3.15+.
|
||||
find_package(MPI REQUIRED MODULE)
|
||||
else()
|
||||
#clunky but we need to make sure we use the upstream module if it exists
|
||||
set(orig_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
|
||||
set(CMAKE_MODULE_PATH "")
|
||||
find_package(MPI REQUIRED MODULE)
|
||||
set(CMAKE_MODULE_PATH ${orig_CMAKE_MODULE_PATH})
|
||||
endif()
|
||||
endif()
|
@ -10,9 +10,13 @@
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
include(VTKmCMakeBackports)
|
||||
include(VTKmDeviceAdapters)
|
||||
include(VTKmCPUVectorization)
|
||||
include(VTKmMPI)
|
||||
|
||||
if(VTKm_ENABLE_MPI AND NOT TARGET MPI::MPI_CXX)
|
||||
find_package(MPI REQUIRED MODULE)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# INTERNAL FUNCTIONS
|
||||
|
7
CMake/patches/README.md
Normal file
7
CMake/patches/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# CMake backports
|
||||
|
||||
This directory contains backports from newer CMake versions to help support
|
||||
actually using older CMake versions for building VTK-m. The directory name is the
|
||||
minimum version of CMake for which the contained files are no longer necessary.
|
||||
For example, the files under the `3.15` directory are not needed for 3.15 or
|
||||
3.16, but are for 3.14.
|
@ -108,6 +108,11 @@ vtkm_option(VTKm_ENABLE_LOGGING "Enable VTKm Logging" ON)
|
||||
# performance.
|
||||
vtkm_option(VTKm_NO_ASSERT "Disable assertions in debugging builds." OFF)
|
||||
|
||||
# The CUDA compiler (as of CUDA 11) takes a surprising long time to compile
|
||||
# kernels with assert in them. By default we turn off asserts when compiling
|
||||
# for CUDA devices.
|
||||
vtkm_option(VTKm_NO_ASSERT_CUDA "Disable assertions for CUDA devices." ON)
|
||||
|
||||
# When VTK-m is embedded into larger projects that wish to make end user
|
||||
# applications they want to only install libraries and don't want CMake/headers
|
||||
# installed.
|
||||
@ -135,6 +140,7 @@ vtkm_option(VTKm_NO_INSTALL_README_LICENSE "disable the installation of README a
|
||||
mark_as_advanced(
|
||||
VTKm_ENABLE_LOGGING
|
||||
VTKm_NO_ASSERT
|
||||
VTKm_NO_ASSERT_CUDA
|
||||
VTKm_INSTALL_ONLY_LIBRARIES
|
||||
VTKm_HIDE_PRIVATE_SYMBOLS
|
||||
VTKm_ENABLE_DEVELOPER_FLAGS
|
||||
@ -266,8 +272,9 @@ if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
|
||||
# Install helper configure files.
|
||||
install(
|
||||
FILES
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmCMakeBackports.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/FindTBB.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/FindMPI.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/patches/3.15/FindMPI.cmake
|
||||
DESTINATION ${VTKm_INSTALL_CMAKE_MODULE_DIR}
|
||||
)
|
||||
|
||||
@ -279,7 +286,6 @@ if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmDeviceAdapters.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmDIYUtils.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmExportHeaderTemplate.h.in
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmMPI.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmRenderingContexts.cmake
|
||||
${VTKm_SOURCE_DIR}/CMake/VTKmWrappers.cmake
|
||||
DESTINATION ${VTKm_INSTALL_CMAKE_MODULE_DIR}
|
||||
@ -313,7 +319,7 @@ endif ()
|
||||
#-----------------------------------------------------------------------------
|
||||
#add the benchmarking folder
|
||||
if(VTKm_ENABLE_BENCHMARKS)
|
||||
add_subdirectory(benchmarking)
|
||||
add_subdirectory(benchmarking)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
3
data/data/rectilinear/fishtank.vtk
Normal file
3
data/data/rectilinear/fishtank.vtk
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ef3dfd79f0c8d18780d0749014d71c0226134041283d33de0bcd994e343dd421
|
||||
size 2001070
|
3
data/data/rectilinear/fishtank_double_ascii.vtk
Normal file
3
data/data/rectilinear/fishtank_double_ascii.vtk
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2bb3d36ea5ecef5e7ef1057d0dddebbc590424915083091ead3dac2928000524
|
||||
size 2904465
|
3
data/data/rectilinear/fishtank_double_big_endian.vtk
Normal file
3
data/data/rectilinear/fishtank_double_big_endian.vtk
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bffad7dae3dd6ef018ad7a9e109464ced0f3b9bc15cf1fb5d555f6d0d00b621f
|
||||
size 3001624
|
3
data/data/rectilinear/fusion.vtk
Normal file
3
data/data/rectilinear/fusion.vtk
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2cbdf56fd5445ddc5b6bc05507b8825fb8d74fe1ccce894bde03e5ff2ecf5fb6
|
||||
size 525141
|
@ -259,22 +259,3 @@ sudo docker login --username=<docker_hub_name>
|
||||
cd .gitlab/ci/docker
|
||||
sudo ./update_all.sh 20201230
|
||||
```
|
||||
|
||||
# ECP OSTI CI
|
||||
|
||||
`.gitlab-ci-ecp.yml` allows for VTK-m to run CI on provided by ECP at NMC.
|
||||
|
||||
To have this work properly you will need to make sure that the gitlab repository
|
||||
has been updated to this non-standard yaml file location
|
||||
( "Settings" -> "CI/CD" -> "General pipelines" -> "Custom CI configuration path").
|
||||
|
||||
The ECP CI is setup to verify VTK-m mainly on Power9 hardware as that currently is
|
||||
missing from VTK-m standard CI infrastructure.
|
||||
|
||||
Currently we verify Power9 support with `cuda` and `openmp` builders. The `cuda` builder
|
||||
is setup to use the default cuda SDK on the machine and the required `c++` compiler which
|
||||
currently is `gcc-4.8.5`. The `openmp` builder is setup to use the newest `c++` compiler provided
|
||||
on the machine so that we maximimze compiler coverage.
|
||||
|
||||
## Issues
|
||||
Currently these builders don't report back to the VTK-m CDash instance.
|
||||
|
10
docs/changelog/cuda-no-assert.md
Normal file
10
docs/changelog/cuda-no-assert.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Disable asserts for CUDA architecture builds
|
||||
|
||||
`assert` is supported on recent CUDA cards, but compiling it appears to be
|
||||
very slow. By default, the `VTKM_ASSERT` macro has been disabled whenever
|
||||
compiling for a CUDA device (i.e. when `__CUDA_ARCH__` is defined).
|
||||
|
||||
Asserts for CUDA devices can be turned back on by turning the
|
||||
`VTKm_NO_ASSERT_CUDA` CMake variable off. Turning this CMake variable off
|
||||
will enable assertions in CUDA kernels unless there is another reason
|
||||
turning off all asserts (such as a release build).
|
@ -15,6 +15,15 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// Pick up conditions where we want to turn on/off assert.
|
||||
#ifndef VTKM_NO_ASSERT
|
||||
#if defined(NDEBUG)
|
||||
#define VTKM_NO_ASSERT
|
||||
#elif defined(__CUDA_ARCH__) && defined(VTKM_NO_ASSERT_CUDA)
|
||||
#define VTKM_NO_ASSERT
|
||||
#endif
|
||||
#endif // VTKM_NO_ASSERT
|
||||
|
||||
/// \def VTKM_ASSERT(condition)
|
||||
///
|
||||
/// Asserts that \a condition resolves to true. If \a condition is false,
|
||||
@ -28,11 +37,7 @@
|
||||
///
|
||||
/// The VTKM_NO_ASSERT cmake and preprocessor option allows debugging builds
|
||||
/// to remove assertions for performance reasons.
|
||||
#if defined(VTKM_CUDA_VERSION_MAJOR) && (VTKM_CUDA_VERSION_MAJOR == 7)
|
||||
//CUDA 7.5 doesn't support assert in device code
|
||||
#define VTKM_ASSERT(condition) (void)(condition)
|
||||
#elif !defined(NDEBUG) && !defined(VTKM_NO_ASSERT)
|
||||
//Only assert if we are in debug mode and don't have VTKM_NO_ASSERT defined
|
||||
#ifndef VTKM_NO_ASSERT
|
||||
#define VTKM_ASSERT(condition) assert(condition)
|
||||
#define VTKM_ASSERTS_CHECKED
|
||||
#else
|
||||
|
@ -55,6 +55,11 @@ struct Bitset
|
||||
return ((this->Mask & (static_cast<MaskType>(1) << bitIndex)) != 0);
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT bool operator==(const vtkm::Bitset<MaskType>& otherBitset) const
|
||||
{
|
||||
return this->Mask == otherBitset.Mask;
|
||||
}
|
||||
|
||||
private:
|
||||
MaskType Mask = 0;
|
||||
};
|
||||
|
101
vtkm/Math.h
101
vtkm/Math.h
@ -17,8 +17,10 @@
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
#include <limits> // must be found with or without CUDA.
|
||||
#ifndef VTKM_CUDA
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@ -2584,6 +2586,105 @@ inline VTKM_EXEC_CONT vtkm::Float64 Ldexp(vtkm::Float64 x, vtkm::Int32 exponent)
|
||||
#endif
|
||||
}
|
||||
|
||||
// See: https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/ for why this works.
|
||||
inline VTKM_EXEC_CONT vtkm::UInt64 FloatDistance(vtkm::Float64 x, vtkm::Float64 y)
|
||||
{
|
||||
static_assert(sizeof(vtkm::Float64) == sizeof(vtkm::UInt64), "vtkm::Float64 is incorrect size.");
|
||||
static_assert(std::numeric_limits<vtkm::Float64>::has_denorm == std::denorm_present, "FloatDistance presumes the floating-point type has subnormal numbers.");
|
||||
|
||||
if (!vtkm::IsFinite(x) || !vtkm::IsFinite(y)) {
|
||||
return 0xFFFFFFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
// Signed zero is the sworn enemy of this process.
|
||||
if (y == 0) {
|
||||
y = vtkm::Abs(y);
|
||||
}
|
||||
if (x == 0) {
|
||||
x = vtkm::Abs(x);
|
||||
}
|
||||
|
||||
if ( (x < 0 && y >= 0) || (x >= 0 && y < 0) )
|
||||
{
|
||||
vtkm::UInt64 dx, dy;
|
||||
if (x < 0) {
|
||||
dy = FloatDistance(0.0, y);
|
||||
dx = FloatDistance(0.0, -x);
|
||||
}
|
||||
else {
|
||||
dy = FloatDistance(0.0, -y);
|
||||
dx = FloatDistance(0.0, x);
|
||||
}
|
||||
|
||||
return dx + dy;
|
||||
}
|
||||
|
||||
if (x < 0 && y < 0) {
|
||||
return FloatDistance(-x, -y);
|
||||
}
|
||||
|
||||
// Note that:
|
||||
// int64_t xi = *reinterpret_cast<int64_t*>(&x);
|
||||
// int64_t yi = *reinterpret_cast<int64_t*>(&y);
|
||||
// also works, but generates warnings.
|
||||
// Good option to have if we get compile errors off memcpy or don't want to #include <cstring> though.
|
||||
// At least on gcc, both versions generate the same assembly.
|
||||
vtkm::UInt64 xi;
|
||||
vtkm::UInt64 yi;
|
||||
memcpy(&xi, &x, sizeof(vtkm::UInt64));
|
||||
memcpy(&yi, &y, sizeof(vtkm::UInt64));
|
||||
if (yi > xi) {
|
||||
return yi - xi;
|
||||
}
|
||||
return xi - yi;
|
||||
}
|
||||
|
||||
inline VTKM_EXEC_CONT vtkm::UInt64 FloatDistance(vtkm::Float32 x, vtkm::Float32 y)
|
||||
{
|
||||
static_assert(sizeof(vtkm::Float32) == sizeof(vtkm::Int32), "vtkm::Float32 is incorrect size.");
|
||||
static_assert(std::numeric_limits<vtkm::Float32>::has_denorm == std::denorm_present, "FloatDistance presumes the floating-point type has subnormal numbers.");
|
||||
|
||||
if (!vtkm::IsFinite(x) || !vtkm::IsFinite(y)) {
|
||||
return 0xFFFFFFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
if (y == 0) {
|
||||
y = vtkm::Abs(y);
|
||||
}
|
||||
if (x == 0) {
|
||||
x = vtkm::Abs(x);
|
||||
}
|
||||
|
||||
if ( (x < 0 && y >= 0) || (x >= 0 && y < 0) )
|
||||
{
|
||||
vtkm::UInt64 dx, dy;
|
||||
if (x < 0) {
|
||||
dy = FloatDistance(0.0f, y);
|
||||
dx = FloatDistance(0.0f, -x);
|
||||
}
|
||||
else {
|
||||
dy = FloatDistance(0.0f, -y);
|
||||
dx = FloatDistance(0.0f, x);
|
||||
}
|
||||
return dx + dy;
|
||||
}
|
||||
|
||||
if (x < 0 && y < 0) {
|
||||
return FloatDistance(-x, -y);
|
||||
}
|
||||
|
||||
vtkm::UInt32 xi_32;
|
||||
vtkm::UInt32 yi_32;
|
||||
memcpy(&xi_32, &x, sizeof(vtkm::UInt32));
|
||||
memcpy(&yi_32, &y, sizeof(vtkm::UInt32));
|
||||
vtkm::UInt64 xi = xi_32;
|
||||
vtkm::UInt64 yi = yi_32;
|
||||
if (yi > xi) {
|
||||
return yi - xi;
|
||||
}
|
||||
return xi - yi;
|
||||
}
|
||||
|
||||
/// Bitwise operations
|
||||
///
|
||||
|
||||
|
101
vtkm/Math.h.in
101
vtkm/Math.h.in
@ -29,8 +29,10 @@ $# Ignore the following comment. It is meant for the generated file.
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
#include <limits> // must be found with or without CUDA.
|
||||
#ifndef VTKM_CUDA
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@ -1186,6 +1188,105 @@ inline VTKM_EXEC_CONT vtkm::Float64 Ldexp(vtkm::Float64 x, vtkm::Int32 exponent)
|
||||
#endif
|
||||
}
|
||||
|
||||
// See: https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/ for why this works.
|
||||
inline VTKM_EXEC_CONT vtkm::UInt64 FloatDistance(vtkm::Float64 x, vtkm::Float64 y)
|
||||
{
|
||||
static_assert(sizeof(vtkm::Float64) == sizeof(vtkm::UInt64), "vtkm::Float64 is incorrect size.");
|
||||
static_assert(std::numeric_limits<vtkm::Float64>::has_denorm == std::denorm_present, "FloatDistance presumes the floating-point type has subnormal numbers.");
|
||||
|
||||
if (!vtkm::IsFinite(x) || !vtkm::IsFinite(y)) {
|
||||
return 0xFFFFFFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
// Signed zero is the sworn enemy of this process.
|
||||
if (y == 0) {
|
||||
y = vtkm::Abs(y);
|
||||
}
|
||||
if (x == 0) {
|
||||
x = vtkm::Abs(x);
|
||||
}
|
||||
|
||||
if ( (x < 0 && y >= 0) || (x >= 0 && y < 0) )
|
||||
{
|
||||
vtkm::UInt64 dx, dy;
|
||||
if (x < 0) {
|
||||
dy = FloatDistance(0.0, y);
|
||||
dx = FloatDistance(0.0, -x);
|
||||
}
|
||||
else {
|
||||
dy = FloatDistance(0.0, -y);
|
||||
dx = FloatDistance(0.0, x);
|
||||
}
|
||||
|
||||
return dx + dy;
|
||||
}
|
||||
|
||||
if (x < 0 && y < 0) {
|
||||
return FloatDistance(-x, -y);
|
||||
}
|
||||
|
||||
// Note that:
|
||||
// int64_t xi = *reinterpret_cast<int64_t*>(&x);
|
||||
// int64_t yi = *reinterpret_cast<int64_t*>(&y);
|
||||
// also works, but generates warnings.
|
||||
// Good option to have if we get compile errors off memcpy or don't want to #include <cstring> though.
|
||||
// At least on gcc, both versions generate the same assembly.
|
||||
vtkm::UInt64 xi;
|
||||
vtkm::UInt64 yi;
|
||||
memcpy(&xi, &x, sizeof(vtkm::UInt64));
|
||||
memcpy(&yi, &y, sizeof(vtkm::UInt64));
|
||||
if (yi > xi) {
|
||||
return yi - xi;
|
||||
}
|
||||
return xi - yi;
|
||||
}
|
||||
|
||||
inline VTKM_EXEC_CONT vtkm::UInt64 FloatDistance(vtkm::Float32 x, vtkm::Float32 y)
|
||||
{
|
||||
static_assert(sizeof(vtkm::Float32) == sizeof(vtkm::Int32), "vtkm::Float32 is incorrect size.");
|
||||
static_assert(std::numeric_limits<vtkm::Float32>::has_denorm == std::denorm_present, "FloatDistance presumes the floating-point type has subnormal numbers.");
|
||||
|
||||
if (!vtkm::IsFinite(x) || !vtkm::IsFinite(y)) {
|
||||
return 0xFFFFFFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
if (y == 0) {
|
||||
y = vtkm::Abs(y);
|
||||
}
|
||||
if (x == 0) {
|
||||
x = vtkm::Abs(x);
|
||||
}
|
||||
|
||||
if ( (x < 0 && y >= 0) || (x >= 0 && y < 0) )
|
||||
{
|
||||
vtkm::UInt64 dx, dy;
|
||||
if (x < 0) {
|
||||
dy = FloatDistance(0.0f, y);
|
||||
dx = FloatDistance(0.0f, -x);
|
||||
}
|
||||
else {
|
||||
dy = FloatDistance(0.0f, -y);
|
||||
dx = FloatDistance(0.0f, x);
|
||||
}
|
||||
return dx + dy;
|
||||
}
|
||||
|
||||
if (x < 0 && y < 0) {
|
||||
return FloatDistance(-x, -y);
|
||||
}
|
||||
|
||||
vtkm::UInt32 xi_32;
|
||||
vtkm::UInt32 yi_32;
|
||||
memcpy(&xi_32, &x, sizeof(vtkm::UInt32));
|
||||
memcpy(&yi_32, &y, sizeof(vtkm::UInt32));
|
||||
vtkm::UInt64 xi = xi_32;
|
||||
vtkm::UInt64 yi = yi_32;
|
||||
if (yi > xi) {
|
||||
return yi - xi;
|
||||
}
|
||||
return xi - yi;
|
||||
}
|
||||
|
||||
/// Bitwise operations
|
||||
///
|
||||
|
||||
|
@ -72,7 +72,7 @@ using IsValidArrayHandle =
|
||||
/// with C++11 type_traits.
|
||||
///
|
||||
template <typename T, typename StorageTag>
|
||||
using IsInValidArrayHandle =
|
||||
using IsInvalidArrayHandle =
|
||||
std::integral_constant<bool, !IsValidArrayHandle<T, StorageTag>::value>;
|
||||
|
||||
/// Checks to see if the ArrayHandle allows writing, as some ArrayHandles
|
||||
|
@ -98,6 +98,7 @@ set(headers
|
||||
Initialize.h
|
||||
Invoker.h
|
||||
Logging.h
|
||||
ParticleArrayCopy.h
|
||||
PartitionedDataSet.h
|
||||
PointLocator.h
|
||||
PointLocatorUniformGrid.h
|
||||
@ -149,6 +150,7 @@ set(sources
|
||||
internal/VirtualObjectTransfer.cxx
|
||||
Initialize.cxx
|
||||
Logging.cxx
|
||||
ParticleArrayCopy.cxx
|
||||
RuntimeDeviceTracker.cxx
|
||||
StorageBasic.cxx
|
||||
Token.cxx
|
||||
@ -183,6 +185,7 @@ set(sources
|
||||
Field.cxx
|
||||
FieldRangeCompute.cxx
|
||||
FieldRangeGlobalCompute.cxx
|
||||
ParticleArrayCopy.cxx
|
||||
PartitionedDataSet.cxx
|
||||
PointLocator.cxx
|
||||
PointLocatorUniformGrid.cxx
|
||||
|
90
vtkm/cont/ParticleArrayCopy.cxx
Normal file
90
vtkm/cont/ParticleArrayCopy.cxx
Normal file
@ -0,0 +1,90 @@
|
||||
//============================================================================
|
||||
// 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/Invoker.h>
|
||||
#include <vtkm/cont/ParticleArrayCopy.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct CopyParticlePositionWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn inParticle, FieldOut outPos);
|
||||
|
||||
VTKM_EXEC void operator()(const vtkm::Particle& inParticle, vtkm::Vec3f& outPos) const
|
||||
{
|
||||
outPos = inParticle.Pos;
|
||||
}
|
||||
};
|
||||
|
||||
struct CopyParticleAllWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn inParticle,
|
||||
FieldOut outPos,
|
||||
FieldOut outID,
|
||||
FieldOut outSteps,
|
||||
FieldOut outStatus,
|
||||
FieldOut outTime);
|
||||
|
||||
VTKM_EXEC void operator()(const vtkm::Particle& inParticle,
|
||||
vtkm::Vec3f& outPos,
|
||||
vtkm::Id& outID,
|
||||
vtkm::Id& outSteps,
|
||||
vtkm::ParticleStatus& outStatus,
|
||||
vtkm::FloatDefault& outTime) const
|
||||
{
|
||||
outPos = inParticle.Pos;
|
||||
outID = inParticle.ID;
|
||||
outSteps = inParticle.NumSteps;
|
||||
outStatus = inParticle.Status;
|
||||
outTime = inParticle.Time;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
VTKM_CONT void ParticleArrayCopy(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos)
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
detail::CopyParticlePositionWorklet worklet;
|
||||
|
||||
invoke(worklet, inP, outPos);
|
||||
}
|
||||
|
||||
/// \brief Copy all fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
/// position, ID, number of steps, status and time into a separate
|
||||
/// \c ArrayHandle.
|
||||
///
|
||||
|
||||
|
||||
VTKM_CONT void ParticleArrayCopy(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos,
|
||||
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outID,
|
||||
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outSteps,
|
||||
vtkm::cont::ArrayHandle<vtkm::ParticleStatus, vtkm::cont::StorageTagBasic>& outStatus,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault, vtkm::cont::StorageTagBasic>& outTime)
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
detail::CopyParticleAllWorklet worklet;
|
||||
|
||||
invoke(worklet, inP, outPos, outID, outSteps, outStatus, outTime);
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont
|
49
vtkm/cont/ParticleArrayCopy.h
Normal file
49
vtkm/cont/ParticleArrayCopy.h
Normal file
@ -0,0 +1,49 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_ParticleArrayCopy_h
|
||||
#define vtk_m_cont_ParticleArrayCopy_h
|
||||
|
||||
#include <vtkm/Particle.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/vtkm_cont_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
/// \brief Copy fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
/// position field into an \c ArrayHandle of \c Vec3f objects.
|
||||
///
|
||||
VTKM_CONT_EXPORT
|
||||
VTKM_CONT void ParticleArrayCopy(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos);
|
||||
|
||||
/// \brief Copy all fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
/// position, ID, number of steps, status and time into a separate
|
||||
/// \c ArrayHandle.
|
||||
///
|
||||
VTKM_CONT_EXPORT
|
||||
VTKM_CONT void ParticleArrayCopy(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos,
|
||||
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outID,
|
||||
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outSteps,
|
||||
vtkm::cont::ArrayHandle<vtkm::ParticleStatus, vtkm::cont::StorageTagBasic>& outStatus,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault, vtkm::cont::StorageTagBasic>& outTime);
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
#endif //vtk_m_cont_ParticleArrayCopy_h
|
@ -30,6 +30,176 @@ namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
/// \brief VariantArrayHandle superclass holding common operations.
|
||||
///
|
||||
/// `VariantArrayHandleCommon` is a superclass to all `VariantArrayHandleBase`
|
||||
/// and `VariantArrayHandle` classes. It contains all operations that are
|
||||
/// independent of the type lists defined for these templated class or has
|
||||
/// versions of methods that allow you to specify type lists.
|
||||
///
|
||||
/// See the documentation of `VariantArrayHandleBase` for more information.
|
||||
///
|
||||
class VTKM_ALWAYS_EXPORT VariantArrayHandleCommon
|
||||
{
|
||||
std::shared_ptr<vtkm::cont::internal::VariantArrayHandleContainerBase> ArrayContainer;
|
||||
|
||||
public:
|
||||
VTKM_CONT VariantArrayHandleCommon() = default;
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT VariantArrayHandleCommon(const vtkm::cont::ArrayHandle<T, Storage>& array)
|
||||
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(
|
||||
vtkm::cont::ArrayHandleVirtual<T>{ array }))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT VariantArrayHandleCommon(
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>& array)
|
||||
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(array))
|
||||
{
|
||||
}
|
||||
|
||||
/// Returns true if this array matches the array handle type passed in.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT bool IsType() const
|
||||
{
|
||||
return internal::variant::IsType<ArrayHandleType>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// Returns true if this array matches the ValueType type passed in.
|
||||
///
|
||||
template <typename T>
|
||||
VTKM_CONT bool IsValueType() const
|
||||
{
|
||||
return internal::variant::IsValueType<T>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// Returns this array cast to the given \c ArrayHandle type. Throws \c
|
||||
/// ErrorBadType if the cast does not work. Use \c IsType
|
||||
/// to check if the cast can happen.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT ArrayHandleType Cast() const
|
||||
{
|
||||
return internal::variant::Cast<ArrayHandleType>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// \brief Call a functor using the underlying array type.
|
||||
///
|
||||
/// `CastAndCall` 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. (Note that this
|
||||
/// calling differs from that of the `CastAndCall` methods of subclasses.)
|
||||
///
|
||||
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCall(Functor&& functor, Args&&... args) const;
|
||||
|
||||
/// Returns this array cast to a `ArrayHandleVirtual` of the given type.
|
||||
/// This will perform type conversions as necessary, and will log warnings
|
||||
/// if the conversion is lossy.
|
||||
///
|
||||
/// This method internally uses `CastAndCall`. A custom storage tag list may
|
||||
/// be specified in the second template parameter, which will be passed to
|
||||
/// the CastAndCall. You can also specify a list of types to try as the optional
|
||||
/// third template argument.
|
||||
///
|
||||
template <typename T,
|
||||
typename StorageList = VTKM_DEFAULT_STORAGE_LIST,
|
||||
typename TypeList = vtkm::List<T>>
|
||||
VTKM_CONT vtkm::cont::ArrayHandleVirtual<T> AsVirtual() const
|
||||
{
|
||||
VTKM_IS_LIST(StorageList);
|
||||
VTKM_IS_LIST(TypeList);
|
||||
vtkm::cont::internal::variant::ForceCastToVirtual caster;
|
||||
vtkm::cont::ArrayHandleVirtual<T> output;
|
||||
this->CastAndCall<TypeList, StorageList>(caster, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Returns this array cast to a `ArrayHandleMultiplexer` of the given type.
|
||||
/// This will attempt to cast the internal array to each supported type of
|
||||
/// the multiplexer. If none are supported, an invalid ArrayHandleMultiplexer
|
||||
/// is returned.
|
||||
///
|
||||
/// As a special case, if one of the arrays in the `ArrayHandleMultiplexer`'s
|
||||
/// type list is an `ArrayHandleCast`, then the multiplexer will look for type
|
||||
/// type of array being cast rather than an actual cast array.
|
||||
///
|
||||
///@{
|
||||
template <typename... T>
|
||||
VTKM_CONT void AsMultiplexer(vtkm::cont::ArrayHandleMultiplexer<T...>& result) const;
|
||||
|
||||
template <typename ArrayHandleMultiplexerType>
|
||||
VTKM_CONT ArrayHandleMultiplexerType AsMultiplexer() const
|
||||
{
|
||||
ArrayHandleMultiplexerType result;
|
||||
this->AsMultiplexer(result);
|
||||
return result;
|
||||
}
|
||||
///@}
|
||||
|
||||
/// Given a references to an ArrayHandle object, casts this array to the
|
||||
/// ArrayHandle's type and sets the given ArrayHandle to this array. Throws
|
||||
/// `ErrorBadType` if the cast does not work. Use `IsType` to check
|
||||
/// if the cast can happen.
|
||||
///
|
||||
/// Note that this is a shallow copy. The data are not copied and a change
|
||||
/// in the data in one array will be reflected in the other.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT void CopyTo(ArrayHandleType& array) const
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
||||
array = this->Cast<ArrayHandleType>();
|
||||
}
|
||||
|
||||
/// \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 variant array handle for it. This method is convenient when
|
||||
/// creating output arrays that should be the same type as some input array.
|
||||
///
|
||||
VTKM_CONT VariantArrayHandleCommon NewInstance() const
|
||||
{
|
||||
VariantArrayHandleCommon instance;
|
||||
instance.ArrayContainer = this->ArrayContainer->NewInstance();
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Releases any resources being used in the execution environment (that are
|
||||
/// not being shared by the control environment).
|
||||
///
|
||||
void ReleaseResourcesExecution() { return this->ArrayContainer->ReleaseResourcesExecution(); }
|
||||
|
||||
|
||||
/// Releases all resources in both the control and execution environments.
|
||||
///
|
||||
void ReleaseResources() { return this->ArrayContainer->ReleaseResources(); }
|
||||
|
||||
/// \brief Get the number of components in each array value.
|
||||
///
|
||||
/// This method will query the array type for the number of components in
|
||||
/// each value of the array. The number of components is determined by
|
||||
/// the \c VecTraits::NUM_COMPONENTS trait class.
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return this->ArrayContainer->GetNumberOfComponents();
|
||||
}
|
||||
|
||||
/// \brief Get the number of values in the array.
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::Id GetNumberOfValues() const { return this->ArrayContainer->GetNumberOfValues(); }
|
||||
|
||||
VTKM_CONT
|
||||
void PrintSummary(std::ostream& out) const { this->ArrayContainer->PrintSummary(out); }
|
||||
};
|
||||
|
||||
/// \brief Holds an array handle without having to specify template parameters.
|
||||
///
|
||||
/// \c VariantArrayHandle holds an \c ArrayHandle or \c ArrayHandleVirtual
|
||||
@ -61,32 +231,25 @@ namespace cont
|
||||
/// component types.
|
||||
///
|
||||
template <typename TypeList>
|
||||
class VTKM_ALWAYS_EXPORT VariantArrayHandleBase
|
||||
class VTKM_ALWAYS_EXPORT VariantArrayHandleBase : public VariantArrayHandleCommon
|
||||
{
|
||||
VTKM_STATIC_ASSERT_MSG((!std::is_same<TypeList, vtkm::ListUniversal>::value),
|
||||
"Cannot use vtkm::ListUniversal with VariantArrayHandle.");
|
||||
|
||||
using Superclass = VariantArrayHandleCommon;
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
VariantArrayHandleBase() = default;
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT VariantArrayHandleBase(const vtkm::cont::ArrayHandle<T, Storage>& array)
|
||||
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(
|
||||
vtkm::cont::ArrayHandleVirtual<T>{ array }))
|
||||
: Superclass(array)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
explicit VTKM_CONT VariantArrayHandleBase(
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>& array)
|
||||
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(array))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename OtherTypeList>
|
||||
VTKM_CONT explicit VariantArrayHandleBase(const VariantArrayHandleBase<OtherTypeList>& src)
|
||||
: ArrayContainer(internal::variant::GetContainer::Extract(src))
|
||||
VTKM_CONT explicit VariantArrayHandleBase(const VariantArrayHandleCommon& src)
|
||||
: Superclass(src)
|
||||
{
|
||||
}
|
||||
|
||||
@ -104,32 +267,6 @@ public:
|
||||
default;
|
||||
|
||||
|
||||
/// Returns true if this array matches the array handle type passed in.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT bool IsType() const
|
||||
{
|
||||
return internal::variant::IsType<ArrayHandleType>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// Returns true if this array matches the ValueType type passed in.
|
||||
///
|
||||
template <typename T>
|
||||
VTKM_CONT bool IsValueType() const
|
||||
{
|
||||
return internal::variant::IsValueType<T>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// Returns this array cast to the given \c ArrayHandle type. Throws \c
|
||||
/// ErrorBadType if the cast does not work. Use \c IsType
|
||||
/// to check if the cast can happen.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT ArrayHandleType Cast() const
|
||||
{
|
||||
return internal::variant::Cast<ArrayHandleType>(this->ArrayContainer.get());
|
||||
}
|
||||
|
||||
/// Returns this array cast to a \c ArrayHandleVirtual of the given type.
|
||||
/// This will perform type conversions as necessary, and will log warnings
|
||||
/// if the conversion is lossy.
|
||||
@ -138,51 +275,10 @@ public:
|
||||
/// be specified in the second template parameter, which will be passed to
|
||||
/// the CastAndCall.
|
||||
///
|
||||
template <typename T, typename StorageTagList = VTKM_DEFAULT_STORAGE_LIST>
|
||||
template <typename T, typename StorageList = VTKM_DEFAULT_STORAGE_LIST>
|
||||
VTKM_CONT vtkm::cont::ArrayHandleVirtual<T> AsVirtual() const
|
||||
{
|
||||
VTKM_IS_LIST(StorageTagList);
|
||||
vtkm::cont::internal::variant::ForceCastToVirtual caster;
|
||||
vtkm::cont::ArrayHandleVirtual<T> output;
|
||||
this->CastAndCall(StorageTagList{}, caster, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Returns this array cast to a \c ArrayHandleMultiplexer of the given type.
|
||||
/// This will attempt to cast the internal array to each supported type of
|
||||
/// the multiplexer. If none are supported, an invalid ArrayHandleMultiplexer
|
||||
/// is returned.
|
||||
///
|
||||
/// As a special case, if one of the arrays in the \c ArrayHandleMultiplexer's
|
||||
/// type list is an \c ArrayHandleCast, then the multiplexer will look for type
|
||||
/// type of array being cast rather than an actual cast array.
|
||||
///
|
||||
///@{
|
||||
template <typename... T>
|
||||
VTKM_CONT void AsMultiplexer(vtkm::cont::ArrayHandleMultiplexer<T...>& result) const;
|
||||
|
||||
template <typename ArrayHandleMultiplexerType>
|
||||
VTKM_CONT ArrayHandleMultiplexerType AsMultiplexer() const
|
||||
{
|
||||
ArrayHandleMultiplexerType result;
|
||||
this->AsMultiplexer(result);
|
||||
return result;
|
||||
}
|
||||
///@}
|
||||
|
||||
/// Given a references to an ArrayHandle object, casts this array to the
|
||||
/// ArrayHandle's type and sets the given ArrayHandle to this array. Throws
|
||||
/// \c ErrorBadType if the cast does not work. Use \c
|
||||
/// ArrayHandleType to check if the cast can happen.
|
||||
///
|
||||
/// Note that this is a shallow copy. The data are not copied and a change
|
||||
/// in the data in one array will be reflected in the other.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT void CopyTo(ArrayHandleType& array) const
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
||||
array = this->Cast<ArrayHandleType>();
|
||||
return this->Superclass::AsVirtual<T, StorageList, TypeList>();
|
||||
}
|
||||
|
||||
/// Changes the types to try casting to when resolving this variant array,
|
||||
@ -202,7 +298,7 @@ public:
|
||||
//@{
|
||||
/// \brief Call a functor using the underlying array type.
|
||||
///
|
||||
/// \c CastAndCall Attempts to cast the held array to a specific value type,
|
||||
/// `CastAndCall` attempts to cast the held array to a specific value type,
|
||||
/// then call the given functor with the cast array. The types
|
||||
/// tried in the cast are those in the lists defined by the TypeList.
|
||||
/// By default \c VariantArrayHandle set this to \c VTKM_DEFAULT_TYPE_LIST.
|
||||
@ -245,59 +341,25 @@ public:
|
||||
/// returns a new variant array handle for it. This method is convenient when
|
||||
/// creating output arrays that should be the same type as some input array.
|
||||
///
|
||||
VTKM_CONT
|
||||
VariantArrayHandleBase<TypeList> NewInstance() const
|
||||
VTKM_CONT VariantArrayHandleBase<TypeList> NewInstance() const
|
||||
{
|
||||
VariantArrayHandleBase<TypeList> instance;
|
||||
instance.ArrayContainer = this->ArrayContainer->NewInstance();
|
||||
return instance;
|
||||
return VariantArrayHandleBase<TypeList>(this->Superclass::NewInstance());
|
||||
}
|
||||
|
||||
/// Releases any resources being used in the execution environment (that are
|
||||
/// not being shared by the control environment).
|
||||
///
|
||||
void ReleaseResourcesExecution() { return this->ArrayContainer->ReleaseResourcesExecution(); }
|
||||
|
||||
|
||||
/// Releases all resources in both the control and execution environments.
|
||||
///
|
||||
void ReleaseResources() { return this->ArrayContainer->ReleaseResources(); }
|
||||
|
||||
/// \brief Get the number of components in each array value.
|
||||
///
|
||||
/// This method will query the array type for the number of components in
|
||||
/// each value of the array. The number of components is determined by
|
||||
/// the \c VecTraits::NUM_COMPONENTS trait class.
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return this->ArrayContainer->GetNumberOfComponents();
|
||||
}
|
||||
|
||||
/// \brief Get the number of values in the array.
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::Id GetNumberOfValues() const { return this->ArrayContainer->GetNumberOfValues(); }
|
||||
|
||||
VTKM_CONT
|
||||
void PrintSummary(std::ostream& out) const { this->ArrayContainer->PrintSummary(out); }
|
||||
|
||||
private:
|
||||
friend struct internal::variant::GetContainer;
|
||||
std::shared_ptr<vtkm::cont::internal::VariantArrayHandleContainerBase> ArrayContainer;
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCallImpl(std::false_type, Functor&& f, Args&&... args) const
|
||||
{
|
||||
this->CastAndCallImpl(std::true_type(),
|
||||
VTKM_DEFAULT_STORAGE_LIST(),
|
||||
std::forward<Functor>(f),
|
||||
std::forward<Args>(args)...);
|
||||
this->Superclass::CastAndCall<TypeList, VTKM_DEFAULT_STORAGE_LIST>(std::forward<Functor>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename StorageTagList, typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCallImpl(std::true_type, StorageTagList, Functor&& f, Args&&...) const;
|
||||
template <typename StorageList, typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCallImpl(std::true_type, StorageList, Functor&& f, Args&&... args) const
|
||||
{
|
||||
this->Superclass::CastAndCall<TypeList, StorageList>(std::forward<Functor>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
using VariantArrayHandle = vtkm::cont::VariantArrayHandleBase<VTKM_DEFAULT_TYPE_LIST>;
|
||||
@ -395,7 +457,7 @@ struct IsUndefinedStorage
|
||||
{
|
||||
};
|
||||
template <typename T, typename U>
|
||||
struct IsUndefinedStorage<vtkm::List<T, U>> : vtkm::cont::internal::IsInValidArrayHandle<T, U>
|
||||
struct IsUndefinedStorage<vtkm::List<T, U>> : vtkm::cont::internal::IsInvalidArrayHandle<T, U>
|
||||
{
|
||||
};
|
||||
|
||||
@ -408,12 +470,8 @@ using ListDynamicTypes =
|
||||
|
||||
|
||||
|
||||
template <typename TypeList>
|
||||
template <typename StorageTagList, typename Functor, typename... Args>
|
||||
VTKM_CONT void VariantArrayHandleBase<TypeList>::CastAndCallImpl(std::true_type,
|
||||
StorageTagList,
|
||||
Functor&& f,
|
||||
Args&&... args) const
|
||||
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
|
||||
VTKM_CONT void VariantArrayHandleCommon::CastAndCall(Functor&& f, Args&&... args) const
|
||||
{
|
||||
using crossProduct = detail::ListDynamicTypes<TypeList, StorageTagList>;
|
||||
|
||||
@ -448,9 +506,9 @@ namespace detail
|
||||
|
||||
struct VariantArrayHandleTryMultiplexer
|
||||
{
|
||||
template <typename T, typename Storage, typename... TypeList, typename... ArrayTypes>
|
||||
template <typename T, typename Storage, typename... ArrayTypes>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>&,
|
||||
const vtkm::cont::VariantArrayHandleBase<TypeList...>& self,
|
||||
const vtkm::cont::VariantArrayHandleCommon& self,
|
||||
vtkm::cont::ArrayHandleMultiplexer<ArrayTypes...>& result) const
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, Storage> targetArray;
|
||||
@ -464,15 +522,15 @@ struct VariantArrayHandleTryMultiplexer
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, typename Storage, typename... TypeList>
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void FetchArrayExact(vtkm::cont::ArrayHandle<T, Storage>& targetArray,
|
||||
const vtkm::cont::VariantArrayHandleBase<TypeList...>& self,
|
||||
const vtkm::cont::VariantArrayHandleCommon& self,
|
||||
bool& foundArray) const
|
||||
{
|
||||
using ArrayType = vtkm::cont::ArrayHandle<T, Storage>;
|
||||
if (self.template IsType<ArrayType>())
|
||||
if (self.IsType<ArrayType>())
|
||||
{
|
||||
targetArray = self.template Cast<ArrayType>();
|
||||
targetArray = self.Cast<ArrayType>();
|
||||
foundArray = true;
|
||||
}
|
||||
else
|
||||
@ -481,9 +539,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Storage, typename... TypeList>
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void FetchArray(vtkm::cont::ArrayHandle<T, Storage>& targetArray,
|
||||
const vtkm::cont::VariantArrayHandleBase<TypeList...>& self,
|
||||
const vtkm::cont::VariantArrayHandleCommon& self,
|
||||
bool& foundArray,
|
||||
bool vtkmNotUsed(foundArrayInPreviousCall)) const
|
||||
{
|
||||
@ -492,17 +550,13 @@ private:
|
||||
|
||||
// Special condition for transformed arrays. Instead of pulling out the
|
||||
// transform, pull out the array that is being transformed.
|
||||
template <typename T,
|
||||
typename SrcArray,
|
||||
typename ForwardTransform,
|
||||
typename ReverseTransform,
|
||||
typename... TypeList>
|
||||
template <typename T, typename SrcArray, typename ForwardTransform, typename ReverseTransform>
|
||||
VTKM_CONT void FetchArray(
|
||||
vtkm::cont::ArrayHandle<
|
||||
T,
|
||||
vtkm::cont::internal::StorageTagTransform<SrcArray, ForwardTransform, ReverseTransform>>&
|
||||
targetArray,
|
||||
const vtkm::cont::VariantArrayHandleBase<TypeList...>& self,
|
||||
const vtkm::cont::VariantArrayHandleCommon& self,
|
||||
bool& foundArray,
|
||||
bool foundArrayInPreviousCall) const
|
||||
{
|
||||
@ -526,11 +580,11 @@ private:
|
||||
|
||||
// Special condition for cast arrays. Instead of pulling out an ArrayHandleCast, pull out
|
||||
// the array that is being cast.
|
||||
template <typename TargetT, typename SourceT, typename SourceStorage, typename... TypeList>
|
||||
template <typename TargetT, typename SourceT, typename SourceStorage>
|
||||
VTKM_CONT void FetchArray(
|
||||
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>&
|
||||
targetArray,
|
||||
const vtkm::cont::VariantArrayHandleBase<TypeList...>& self,
|
||||
const vtkm::cont::VariantArrayHandleCommon& self,
|
||||
bool& foundArray,
|
||||
bool foundArrayInPreviousCall) const
|
||||
{
|
||||
@ -557,9 +611,8 @@ private:
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename TypeList>
|
||||
template <typename... T>
|
||||
inline VTKM_CONT void VariantArrayHandleBase<TypeList>::AsMultiplexer(
|
||||
inline VTKM_CONT void VariantArrayHandleCommon::AsMultiplexer(
|
||||
vtkm::cont::ArrayHandleMultiplexer<T...>& result) const
|
||||
{
|
||||
// Make sure IsValid is clear
|
||||
|
@ -77,6 +77,7 @@ set(unit_tests
|
||||
UnitTestInitialize.cxx
|
||||
UnitTestLogging.cxx
|
||||
UnitTestMoveConstructors.cxx
|
||||
UnitTestParticleArrayCopy.cxx
|
||||
UnitTestPartitionedDataSet.cxx
|
||||
UnitTestRuntimeDeviceInformation.cxx
|
||||
UnitTestRuntimeDeviceNames.cxx
|
||||
|
@ -130,6 +130,7 @@ public:
|
||||
catch (std::exception& error)
|
||||
{
|
||||
std::cout << "***** STL exception throw." << std::endl << error.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -165,6 +166,7 @@ public:
|
||||
catch (std::exception& error)
|
||||
{
|
||||
std::cout << "***** STL exception throw." << std::endl << error.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
77
vtkm/cont/testing/UnitTestParticleArrayCopy.cxx
Normal file
77
vtkm/cont/testing/UnitTestParticleArrayCopy.cxx
Normal file
@ -0,0 +1,77 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <random>
|
||||
#include <vtkm/cont/ParticleArrayCopy.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
void TestParticleArrayCopy()
|
||||
{
|
||||
std::random_device device;
|
||||
std::default_random_engine generator(static_cast<vtkm::UInt32>(277));
|
||||
vtkm::FloatDefault x0(-1), x1(1);
|
||||
std::uniform_real_distribution<vtkm::FloatDefault> dist(x0, x1);
|
||||
|
||||
std::vector<vtkm::Particle> particles;
|
||||
vtkm::Id N = 17;
|
||||
for (vtkm::Id i = 0; i < N; i++)
|
||||
{
|
||||
auto x = dist(generator);
|
||||
auto y = dist(generator);
|
||||
auto z = dist(generator);
|
||||
particles.push_back(vtkm::Particle(vtkm::Vec3f(x, y, z), i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
auto particleAH = vtkm::cont::make_ArrayHandle(particles);
|
||||
|
||||
//Test copy position only
|
||||
if (i == 0)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> pos;
|
||||
vtkm::cont::ParticleArrayCopy(particleAH, pos);
|
||||
|
||||
auto pPortal = particleAH.ReadPortal();
|
||||
for (vtkm::Id j = 0; j < N; j++)
|
||||
{
|
||||
auto p = pPortal.Get(j);
|
||||
auto pt = pos.ReadPortal().Get(j);
|
||||
VTKM_TEST_ASSERT(p.Pos == pt, "Positions do not match");
|
||||
}
|
||||
}
|
||||
else //Test copy everything
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> pos;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> ids, steps;
|
||||
vtkm::cont::ArrayHandle<vtkm::ParticleStatus> status;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> ptime;
|
||||
|
||||
vtkm::cont::ParticleArrayCopy(particleAH, pos, ids, steps, status, ptime);
|
||||
|
||||
auto pPortal = particleAH.ReadPortal();
|
||||
for (vtkm::Id j = 0; j < N; j++)
|
||||
{
|
||||
auto p = pPortal.Get(j);
|
||||
auto pt = pos.ReadPortal().Get(j);
|
||||
VTKM_TEST_ASSERT(p.Pos == pt, "Positions do not match");
|
||||
VTKM_TEST_ASSERT(p.ID == ids.ReadPortal().Get(j), "IDs do not match");
|
||||
VTKM_TEST_ASSERT(p.NumSteps == steps.ReadPortal().Get(j), "Steps do not match");
|
||||
VTKM_TEST_ASSERT(p.Status == status.ReadPortal().Get(j), "Steps do not match");
|
||||
VTKM_TEST_ASSERT(p.Time == ptime.ReadPortal().Get(j), "Times do not match");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UnitTestParticleArrayCopy(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(TestParticleArrayCopy, argc, argv);
|
||||
}
|
@ -10,7 +10,6 @@
|
||||
#ifndef vtk_m_exec_Derivative_h
|
||||
#define vtk_m_exec_Derivative_h
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/CellShape.h>
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/ErrorCode.h>
|
||||
|
@ -10,14 +10,12 @@
|
||||
#ifndef vtk_m_exec_CellEdge_h
|
||||
#define vtk_m_exec_CellEdge_h
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/CellShape.h>
|
||||
#include <vtkm/CellTraits.h>
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/ErrorCode.h>
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/internal/Assume.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
|
@ -10,13 +10,11 @@
|
||||
#ifndef vtk_m_exec_CellFace_h
|
||||
#define vtk_m_exec_CellFace_h
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/CellShape.h>
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/ErrorCode.h>
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/internal/Assume.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
|
@ -10,7 +10,6 @@
|
||||
#ifndef vtk_m_exec_Interpolate_h
|
||||
#define vtk_m_exec_Interpolate_h
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/CellShape.h>
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/ErrorCode.h>
|
||||
|
@ -53,6 +53,7 @@ set(headers
|
||||
MeshQuality.h
|
||||
NDEntropy.h
|
||||
NDHistogram.h
|
||||
ParticleAdvection.h
|
||||
Pathline.h
|
||||
PointAverage.h
|
||||
PointElevation.h
|
||||
@ -120,6 +121,7 @@ set(header_template_sources
|
||||
MeshQuality.hxx
|
||||
NDEntropy.hxx
|
||||
NDHistogram.hxx
|
||||
ParticleAdvection.hxx
|
||||
Pathline.hxx
|
||||
PointAverage.hxx
|
||||
PointElevation.hxx
|
||||
|
69
vtkm/filter/ParticleAdvection.h
Normal file
69
vtkm/filter/ParticleAdvection.h
Normal file
@ -0,0 +1,69 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#ifndef vtk_m_filter_ParticleAdvection_h
|
||||
#define vtk_m_filter_ParticleAdvection_h
|
||||
|
||||
#include <vtkm/filter/FilterDataSetWithField.h>
|
||||
#include <vtkm/worklet/ParticleAdvection.h>
|
||||
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
|
||||
#include <vtkm/worklet/particleadvection/Integrators.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace filter
|
||||
{
|
||||
/// \brief advect particles in a vector field.
|
||||
|
||||
/// Takes as input a vector field and seed locations and generates the
|
||||
/// end points for each seed through the vector field.
|
||||
class ParticleAdvection : public vtkm::filter::FilterDataSetWithField<ParticleAdvection>
|
||||
{
|
||||
public:
|
||||
using SupportedTypes = vtkm::TypeListFieldVec3;
|
||||
|
||||
VTKM_CONT
|
||||
ParticleAdvection();
|
||||
|
||||
VTKM_CONT
|
||||
void SetStepSize(vtkm::FloatDefault s) { this->StepSize = s; }
|
||||
|
||||
VTKM_CONT
|
||||
void SetNumberOfSteps(vtkm::Id n) { this->NumberOfSteps = n; }
|
||||
|
||||
VTKM_CONT
|
||||
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds);
|
||||
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
VTKM_CONT vtkm::cont::DataSet DoExecute(
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
|
||||
|
||||
template <typename DerivedPolicy>
|
||||
VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
|
||||
const vtkm::cont::Field& field,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy);
|
||||
|
||||
private:
|
||||
vtkm::Id NumberOfSteps;
|
||||
vtkm::FloatDefault StepSize;
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
|
||||
vtkm::worklet::ParticleAdvection Worklet;
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::filter
|
||||
|
||||
#ifndef vtk_m_filter_ParticleAdvection_hxx
|
||||
#include <vtkm/filter/ParticleAdvection.hxx>
|
||||
#endif
|
||||
|
||||
#endif // vtk_m_filter_ParticleAdvection_h
|
110
vtkm/filter/ParticleAdvection.hxx
Normal file
110
vtkm/filter/ParticleAdvection.hxx
Normal file
@ -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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_filter_ParticleAdvection_hxx
|
||||
#define vtk_m_filter_ParticleAdvection_hxx
|
||||
|
||||
#include <vtkm/filter/ParticleAdvection.h>
|
||||
|
||||
#include <vtkm/cont/ArrayCopy.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/CellSetSingleType.h>
|
||||
#include <vtkm/cont/ErrorFilterExecution.h>
|
||||
#include <vtkm/cont/ParticleArrayCopy.h>
|
||||
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
|
||||
#include <vtkm/worklet/particleadvection/Integrators.h>
|
||||
#include <vtkm/worklet/particleadvection/Particles.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace filter
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline VTKM_CONT ParticleAdvection::ParticleAdvection()
|
||||
: vtkm::filter::FilterDataSetWithField<ParticleAdvection>()
|
||||
, Worklet()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline VTKM_CONT void ParticleAdvection::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds)
|
||||
{
|
||||
this->Seeds = seeds;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
inline VTKM_CONT vtkm::cont::DataSet ParticleAdvection::DoExecute(
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
||||
{
|
||||
//Check for some basics.
|
||||
if (this->Seeds.GetNumberOfValues() == 0)
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution("No seeds provided.");
|
||||
}
|
||||
|
||||
const vtkm::cont::DynamicCellSet& cells = input.GetCellSet();
|
||||
const vtkm::cont::CoordinateSystem& coords =
|
||||
input.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex());
|
||||
|
||||
if (!fieldMeta.IsPointField())
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution("Point field expected.");
|
||||
}
|
||||
|
||||
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
|
||||
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
|
||||
GridEvalType eval(coords, cells, field);
|
||||
RK4Type rk4(eval, this->StepSize);
|
||||
|
||||
vtkm::worklet::ParticleAdvectionResult res;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
|
||||
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
|
||||
res = this->Worklet.Run(rk4, seedArray, this->NumberOfSteps);
|
||||
|
||||
vtkm::cont::DataSet outData;
|
||||
|
||||
//Copy particles to coordinate array
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> outPos;
|
||||
vtkm::cont::ParticleArrayCopy(res.Particles, outPos);
|
||||
|
||||
vtkm::cont::CoordinateSystem outCoords("coordinates", outPos);
|
||||
outData.AddCoordinateSystem(outCoords);
|
||||
|
||||
//Create vertex cell set
|
||||
vtkm::Id numPoints = outPos.GetNumberOfValues();
|
||||
vtkm::cont::CellSetSingleType<> outCells;
|
||||
vtkm::cont::ArrayHandleIndex conn(numPoints);
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
||||
|
||||
vtkm::cont::ArrayCopy(conn, connectivity);
|
||||
outCells.Fill(numPoints, vtkm::CELL_SHAPE_VERTEX, 1, connectivity);
|
||||
outData.SetCellSet(outCells);
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename DerivedPolicy>
|
||||
inline VTKM_CONT bool ParticleAdvection::MapFieldOntoOutput(vtkm::cont::DataSet&,
|
||||
const vtkm::cont::Field&,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::filter
|
||||
#endif
|
@ -80,7 +80,7 @@ template <typename Storage>
|
||||
struct ArrayValidPredicate
|
||||
{
|
||||
template <typename T>
|
||||
using Predicate = vtkm::cont::internal::IsInValidArrayHandle<T, Storage>;
|
||||
using Predicate = vtkm::cont::internal::IsInvalidArrayHandle<T, Storage>;
|
||||
};
|
||||
|
||||
template <typename TargetT, typename Storage, bool Valid>
|
||||
|
@ -46,6 +46,7 @@ set(unit_tests
|
||||
UnitTestMeshQualityFilter.cxx
|
||||
UnitTestNDEntropyFilter.cxx
|
||||
UnitTestNDHistogramFilter.cxx
|
||||
UnitTestParticleAdvectionFilter.cxx
|
||||
UnitTestPartitionedDataSetFilters.cxx
|
||||
UnitTestPartitionedDataSetHistogramFilter.cxx
|
||||
UnitTestPointAverageFilter.cxx
|
||||
|
159
vtkm/filter/testing/UnitTestParticleAdvectionFilter.cxx
Normal file
159
vtkm/filter/testing/UnitTestParticleAdvectionFilter.cxx
Normal file
@ -0,0 +1,159 @@
|
||||
//============================================================================
|
||||
// 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/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/ParticleAdvection.h>
|
||||
#include <vtkm/io/VTKDataSetReader.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
vtkm::cont::DataSet CreateDataSet(const vtkm::Id3& dims, const vtkm::Vec3f& vec)
|
||||
{
|
||||
vtkm::Id numPoints = dims[0] * dims[1] * dims[2];
|
||||
|
||||
std::vector<vtkm::Vec3f> vectorField(static_cast<std::size_t>(numPoints));
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(numPoints); i++)
|
||||
vectorField[i] = vec;
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
|
||||
|
||||
vtkm::cont::DataSet ds = dataSetBuilder.Create(dims);
|
||||
ds.AddPointField("vector", vectorField);
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
void TestBasic()
|
||||
{
|
||||
const vtkm::Id3 dims(5, 5, 5);
|
||||
const vtkm::Vec3f vecX(1, 0, 0);
|
||||
|
||||
vtkm::cont::DataSet ds = CreateDataSet(dims, vecX);
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
|
||||
std::vector<vtkm::Particle> seeds(3);
|
||||
seeds[0] = vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
|
||||
seeds[1] = vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
|
||||
seeds[2] = vtkm::Particle(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
|
||||
|
||||
seedArray = vtkm::cont::make_ArrayHandle(seeds);
|
||||
|
||||
vtkm::filter::ParticleAdvection particleAdvection;
|
||||
|
||||
particleAdvection.SetStepSize(0.1f);
|
||||
particleAdvection.SetNumberOfSteps(20);
|
||||
particleAdvection.SetSeeds(seedArray);
|
||||
|
||||
particleAdvection.SetActiveField("vector");
|
||||
auto output = particleAdvection.Execute(ds);
|
||||
|
||||
//Validate the result is correct.
|
||||
VTKM_TEST_ASSERT(output.GetNumberOfCoordinateSystems() == 1,
|
||||
"Wrong number of coordinate systems in the output dataset");
|
||||
|
||||
vtkm::cont::CoordinateSystem coords = output.GetCoordinateSystem();
|
||||
VTKM_TEST_ASSERT(coords.GetNumberOfPoints() == 3, "Wrong number of coordinates");
|
||||
|
||||
vtkm::cont::DynamicCellSet dcells = output.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == 3, "Wrong number of cells");
|
||||
}
|
||||
|
||||
void TestFile(const std::string& fname,
|
||||
const std::vector<vtkm::Vec3f>& pts,
|
||||
vtkm::FloatDefault stepSize,
|
||||
vtkm::Id maxSteps,
|
||||
const std::vector<vtkm::Vec3f>& endPts)
|
||||
{
|
||||
vtkm::io::VTKDataSetReader reader(fname);
|
||||
vtkm::cont::DataSet ds;
|
||||
try
|
||||
{
|
||||
ds = reader.ReadDataSet();
|
||||
}
|
||||
catch (vtkm::io::ErrorIO& e)
|
||||
{
|
||||
std::string message("Error reading: ");
|
||||
message += fname;
|
||||
message += ", ";
|
||||
message += e.GetMessage();
|
||||
|
||||
VTKM_TEST_FAIL(message.c_str());
|
||||
}
|
||||
vtkm::Id numPoints = static_cast<vtkm::Id>(pts.size());
|
||||
|
||||
std::vector<vtkm::Particle> seeds;
|
||||
for (vtkm::Id i = 0; i < numPoints; i++)
|
||||
seeds.push_back(vtkm::Particle(pts[static_cast<std::size_t>(i)], i));
|
||||
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
|
||||
|
||||
vtkm::filter::ParticleAdvection particleAdvection;
|
||||
particleAdvection.SetStepSize(stepSize);
|
||||
particleAdvection.SetNumberOfSteps(maxSteps);
|
||||
particleAdvection.SetSeeds(seedArray);
|
||||
|
||||
particleAdvection.SetActiveField("vec");
|
||||
auto output = particleAdvection.Execute(ds);
|
||||
|
||||
auto coords = output.GetCoordinateSystem().GetData();
|
||||
vtkm::cont::DynamicCellSet dcells = output.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == numPoints, "Wrong number of cells");
|
||||
VTKM_TEST_ASSERT(dcells.IsType<vtkm::cont::CellSetSingleType<>>(), "Wrong cell type");
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> coordPts;
|
||||
auto cPortal = coords.ReadPortal();
|
||||
|
||||
const vtkm::FloatDefault eps = static_cast<vtkm::FloatDefault>(1e-3);
|
||||
for (vtkm::Id i = 0; i < numPoints; i++)
|
||||
{
|
||||
vtkm::Vec3f e = endPts[static_cast<std::size_t>(i)];
|
||||
vtkm::Vec3f pt = cPortal.Get(i);
|
||||
VTKM_TEST_ASSERT(vtkm::Magnitude(pt - e) <= eps, "Particle advection point is wrong");
|
||||
}
|
||||
}
|
||||
|
||||
void TestParticleAdvectionFilter()
|
||||
{
|
||||
TestBasic();
|
||||
|
||||
std::string basePath = vtkm::cont::testing::Testing::GetTestDataBasePath();
|
||||
|
||||
//Fusion test.
|
||||
std::vector<vtkm::Vec3f> fusionPts, fusionEndPts;
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.6f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.3f));
|
||||
//End point values were generated in VisIt.
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5335789918f, 0.87112802267f, 0.6723330020f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5601879954f, 0.91389900446f, 0.43989110522f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.7004770041f, 0.63193398714f, 0.64524400234f));
|
||||
vtkm::FloatDefault fusionStep = 0.005f;
|
||||
std::string fusionFile = basePath + "/rectilinear/fusion.vtk";
|
||||
|
||||
TestFile(fusionFile, fusionPts, fusionStep, 1000, fusionEndPts);
|
||||
|
||||
//Fishtank test.
|
||||
std::vector<vtkm::Vec3f> fishPts, fishEndPts;
|
||||
fishPts.push_back(vtkm::Vec3f(0.75f, 0.5f, 0.01f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.4f, 0.2f, 0.7f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.5f, 0.3f, 0.8f));
|
||||
//End point values were generated in VisIt.
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7734669447f, 0.4870159328f, 0.8979591727f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7257543206f, 0.1277695596f, 0.7468645573f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.8347796798f, 0.1276152730f, 0.4985143244f));
|
||||
vtkm::FloatDefault fishStep = 0.001f;
|
||||
std::string fishFile = basePath + "/rectilinear/fishtank.vtk";
|
||||
|
||||
TestFile(fishFile, fishPts, fishStep, 100, fishEndPts);
|
||||
}
|
||||
}
|
||||
|
||||
int UnitTestParticleAdvectionFilter(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(TestParticleAdvectionFilter, argc, argv);
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/Pathline.h>
|
||||
#include <vtkm/filter/Streamline.h>
|
||||
#include <vtkm/io/VTKDataSetReader.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -102,10 +103,95 @@ void TestPathline()
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == 3, "Wrong number of cells");
|
||||
}
|
||||
|
||||
void TestStreamlineFile(const std::string& fname,
|
||||
const std::vector<vtkm::Vec3f>& pts,
|
||||
vtkm::FloatDefault stepSize,
|
||||
vtkm::Id maxSteps,
|
||||
const std::vector<vtkm::Vec3f>& endPts)
|
||||
{
|
||||
vtkm::io::VTKDataSetReader reader(fname);
|
||||
vtkm::cont::DataSet ds;
|
||||
try
|
||||
{
|
||||
ds = reader.ReadDataSet();
|
||||
}
|
||||
catch (vtkm::io::ErrorIO& e)
|
||||
{
|
||||
std::string message("Error reading: ");
|
||||
message += fname;
|
||||
message += ", ";
|
||||
message += e.GetMessage();
|
||||
|
||||
VTKM_TEST_FAIL(message.c_str());
|
||||
}
|
||||
vtkm::Id numPoints = static_cast<vtkm::Id>(pts.size());
|
||||
|
||||
std::vector<vtkm::Particle> seeds;
|
||||
for (vtkm::Id i = 0; i < numPoints; i++)
|
||||
seeds.push_back(vtkm::Particle(pts[static_cast<std::size_t>(i)], i));
|
||||
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
|
||||
|
||||
vtkm::filter::Streamline streamline;
|
||||
streamline.SetStepSize(stepSize);
|
||||
streamline.SetNumberOfSteps(maxSteps);
|
||||
streamline.SetSeeds(seedArray);
|
||||
|
||||
streamline.SetActiveField("vec");
|
||||
auto output = streamline.Execute(ds);
|
||||
|
||||
auto coords = output.GetCoordinateSystem().GetData();
|
||||
vtkm::cont::DynamicCellSet dcells = output.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == numPoints, "Wrong number of cells");
|
||||
VTKM_TEST_ASSERT(dcells.IsType<vtkm::cont::CellSetExplicit<>>(), "Wrong cell type");
|
||||
|
||||
auto cells = dcells.Cast<vtkm::cont::CellSetExplicit<>>();
|
||||
auto cPortal = coords.ReadPortal();
|
||||
const vtkm::FloatDefault eps = static_cast<vtkm::FloatDefault>(1e-3);
|
||||
|
||||
for (vtkm::Id i = 0; i < numPoints; i++)
|
||||
{
|
||||
vtkm::Id numPts = cells.GetNumberOfPointsInCell(i);
|
||||
std::vector<vtkm::Id> ids(static_cast<std::size_t>(numPts));
|
||||
cells.GetCellPointIds(i, ids.data());
|
||||
|
||||
vtkm::Vec3f e = endPts[static_cast<std::size_t>(i)];
|
||||
vtkm::Vec3f pt = cPortal.Get(ids[ids.size() - 1]);
|
||||
VTKM_TEST_ASSERT(vtkm::Magnitude(pt - e) <= eps, "Particle advection point is wrong");
|
||||
}
|
||||
}
|
||||
|
||||
void TestStreamlineFilters()
|
||||
{
|
||||
TestStreamline();
|
||||
TestPathline();
|
||||
|
||||
std::string basePath = vtkm::cont::testing::Testing::GetTestDataBasePath();
|
||||
|
||||
//Fusion test.
|
||||
std::vector<vtkm::Vec3f> fusionPts, fusionEndPts;
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.6f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.3f));
|
||||
//End point values were generated in VisIt.
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5335789918f, 0.87112802267f, 0.6723330020f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5601879954f, 0.91389900446f, 0.43989110522f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.7004770041f, 0.63193398714f, 0.64524400234f));
|
||||
vtkm::FloatDefault fusionStep = 0.005f;
|
||||
std::string fusionFile = basePath + "/rectilinear/fusion.vtk";
|
||||
TestStreamlineFile(fusionFile, fusionPts, fusionStep, 1000, fusionEndPts);
|
||||
|
||||
//Fishtank test.
|
||||
std::vector<vtkm::Vec3f> fishPts, fishEndPts;
|
||||
fishPts.push_back(vtkm::Vec3f(0.75f, 0.5f, 0.01f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.4f, 0.2f, 0.7f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.5f, 0.3f, 0.8f));
|
||||
//End point values were generated in VisIt.
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7734669447f, 0.4870159328f, 0.8979591727f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7257543206f, 0.1277695596f, 0.7468645573f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.8347796798f, 0.1276152730f, 0.4985143244f));
|
||||
vtkm::FloatDefault fishStep = 0.001f;
|
||||
std::string fishFile = basePath + "/rectilinear/fishtank.vtk";
|
||||
TestStreamlineFile(fishFile, fishPts, fishStep, 100, fishEndPts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
# that we expect for our C++ defines.
|
||||
|
||||
set(VTKM_NO_ASSERT ${VTKm_NO_ASSERT})
|
||||
set(VTKM_NO_ASSERT_CUDA ${VTKm_NO_ASSERT_CUDA})
|
||||
set(VTKM_USE_DOUBLE_PRECISION ${VTKm_USE_DOUBLE_PRECISION})
|
||||
set(VTKM_USE_64BIT_IDS ${VTKm_USE_64BIT_IDS})
|
||||
|
||||
|
@ -62,6 +62,10 @@
|
||||
#cmakedefine VTKM_NO_ASSERT
|
||||
#endif
|
||||
|
||||
#if !defined(VTKM_NO_ASSERT_CUDA)
|
||||
#cmakedefine VTKM_NO_ASSERT_CUDA
|
||||
#endif
|
||||
|
||||
#if !defined(VTKM_USE_DOUBLE_PRECISION) && !defined(VTKM_NO_DOUBLE_PRECISION)
|
||||
#cmakedefine VTKM_USE_DOUBLE_PRECISION
|
||||
#endif
|
||||
|
@ -46,27 +46,34 @@ void VTKRectilinearGridReader::Read()
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
|
||||
//Read the points.
|
||||
std::string dataType;
|
||||
std::string fileStorageDataType;
|
||||
std::size_t numPoints[3];
|
||||
vtkm::cont::VariantArrayHandle X, Y, Z;
|
||||
|
||||
// Always read coordinates as vtkm::FloatDefault
|
||||
std::string readDataType = vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name();
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[0] >> dataType >> std::ws;
|
||||
this->DataFile->Stream >> tag >> numPoints[0] >> fileStorageDataType >> std::ws;
|
||||
if (tag != "X_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("X_COORDINATES tag not found");
|
||||
X = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[0], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[1] >> dataType >> std::ws;
|
||||
// In binary mode, we must read the data as they are stored in the file.
|
||||
// In text mode we can parse as FloatDefault no matter the precision of the storage.
|
||||
X = this->DoReadArrayVariant(
|
||||
vtkm::cont::Field::Association::ANY, fileStorageDataType, numPoints[0], 1);
|
||||
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[1] >> fileStorageDataType >> std::ws;
|
||||
if (tag != "Y_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Y_COORDINATES tag not found");
|
||||
Y = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[1], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[2] >> dataType >> std::ws;
|
||||
Y = this->DoReadArrayVariant(
|
||||
vtkm::cont::Field::Association::ANY, fileStorageDataType, numPoints[1], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[2] >> fileStorageDataType >> std::ws;
|
||||
if (tag != "Z_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Z_COORDINATES tag not found");
|
||||
Z = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[2], 1);
|
||||
|
||||
Z = this->DoReadArrayVariant(
|
||||
vtkm::cont::Field::Association::ANY, fileStorageDataType, numPoints[2], 1);
|
||||
|
||||
|
||||
if (dim != vtkm::Id3(static_cast<vtkm::Id>(numPoints[0]),
|
||||
static_cast<vtkm::Id>(numPoints[1]),
|
||||
@ -78,14 +85,46 @@ void VTKRectilinearGridReader::Read()
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>
|
||||
coords;
|
||||
|
||||
// We need to store all coordinate arrays as FloatDefault.
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Xc, Yc, Zc;
|
||||
X.CopyTo(Xc);
|
||||
Y.CopyTo(Yc);
|
||||
Z.CopyTo(Zc);
|
||||
// But the VariantArrayHandle has type fileStorageDataType.
|
||||
// If the fileStorageDataType is the same as the storage type, no problem:
|
||||
if (fileStorageDataType == vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name())
|
||||
{
|
||||
X.CopyTo(Xc);
|
||||
Y.CopyTo(Yc);
|
||||
Z.CopyTo(Zc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Two cases if the data in the file differs from FloatDefault:
|
||||
if (fileStorageDataType == "float")
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> Xcf, Ycf, Zcf;
|
||||
X.CopyTo(Xcf);
|
||||
Y.CopyTo(Ycf);
|
||||
Z.CopyTo(Zcf);
|
||||
vtkm::cont::ArrayCopy(Xcf, Xc);
|
||||
vtkm::cont::ArrayCopy(Ycf, Yc);
|
||||
vtkm::cont::ArrayCopy(Zcf, Zc);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64> Xcd, Ycd, Zcd;
|
||||
X.CopyTo(Xcd);
|
||||
Y.CopyTo(Ycd);
|
||||
Z.CopyTo(Zcd);
|
||||
vtkm::cont::ArrayCopy(Xcd, Xc);
|
||||
vtkm::cont::ArrayCopy(Ycd, Yc);
|
||||
vtkm::cont::ArrayCopy(Zcd, Zc);
|
||||
}
|
||||
}
|
||||
// As a postscript to this somewhat branchy code, I thought that X.CopyTo(Xc) should be able to cast to the value_type of Xc.
|
||||
// But that would break the ability to make the cast lazy, and hence if you change it you induce performance bugs.
|
||||
|
||||
coords = vtkm::cont::make_ArrayHandleCartesianProduct(Xc, Yc, Zc);
|
||||
vtkm::cont::CoordinateSystem coordSys("coordinates", coords);
|
||||
this->DataSet.AddCoordinateSystem(coordSys);
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
|
||||
// Read points and cell attributes
|
||||
|
@ -578,6 +578,254 @@ void TestReadingStructuredGridBin()
|
||||
"Incorrect cellset type");
|
||||
}
|
||||
|
||||
void TestReadingFishTank()
|
||||
{
|
||||
std::string fishtank =
|
||||
vtkm::cont::testing::Testing::GetTestDataBasePath() + "/rectilinear/fishtank.vtk";
|
||||
vtkm::cont::DataSet ds = readVTKDataSet(fishtank.c_str());
|
||||
|
||||
// This is information you can glean by running 'strings' on fishtank.vtk:
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().IsType<vtkm::cont::CellSetStructured<3>>(),
|
||||
"Incorrect cellset type");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 50 * 50 * 50, "Incorrect number of points");
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 50 * 50 * 50,
|
||||
"Incorrect number of points (from cell set)");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 2, "Incorrect number of fields");
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec"), "The vtk file has a field 'vec', but the dataset does not.");
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec_magnitude"),
|
||||
"The vtk file has a field 'vec_magnitude', but the dataset does not.");
|
||||
|
||||
// I believe the coordinate system is implicitly given by the first element of X_COORDINATES:
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"Need one and only one coordinate system.");
|
||||
// In order to get the data from the coordinate system, I used the following workflow:
|
||||
// First, I deleted all ascii header lines just past 'X_COORDINATES 50 float'.
|
||||
// Once this is done, I can get the binary data from
|
||||
// $ od -tfF --endian=big fishtank_copy.vtk
|
||||
// The result is:
|
||||
// 0 0.020408163 ... 0.9591837 0.97959185 1
|
||||
// So monotone increasing, bound [0,1].
|
||||
const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem();
|
||||
vtkm::Vec<vtkm::Range, 3> ranges = coordinateSystem.GetRange();
|
||||
vtkm::Range xRange = ranges[0];
|
||||
VTKM_TEST_ASSERT(xRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(xRange.Max == 1);
|
||||
// Do the same past 'Y_COORDINATES 50 float'.
|
||||
// You get exactly the same as the x data.
|
||||
vtkm::Range yRange = ranges[1];
|
||||
VTKM_TEST_ASSERT(yRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(yRange.Max == 1);
|
||||
// And finally, do it past 'Z_COORDINATES 50 float':
|
||||
vtkm::Range zRange = ranges[2];
|
||||
VTKM_TEST_ASSERT(zRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(zRange.Max == 1);
|
||||
|
||||
// Now delete the text up to LOOKUP TABLE default.
|
||||
// I see:
|
||||
// 0 0 0 0 3.5267966 . . .
|
||||
// This is a vector magnitude, so all values must be >= 0.
|
||||
// A cursory glance shows that 124.95 is a large value, so we can sanity check the data with the bounds
|
||||
// [0, ~130].
|
||||
// And if we open the file in Paraview, we can observe the bounds [0, 156.905].
|
||||
const vtkm::cont::Field& vec_magnitude = ds.GetField("vec_magnitude");
|
||||
VTKM_TEST_ASSERT(vec_magnitude.GetName() == "vec_magnitude");
|
||||
VTKM_TEST_ASSERT(vec_magnitude.IsFieldPoint());
|
||||
|
||||
vtkm::Range mag_range;
|
||||
vec_magnitude.GetRange(&mag_range);
|
||||
VTKM_TEST_ASSERT(mag_range.Min == 0);
|
||||
VTKM_TEST_ASSERT(mag_range.Max <= 156.906);
|
||||
|
||||
// This info was gleaned from the Paraview Information panel:
|
||||
const vtkm::cont::Field& vec = ds.GetField("vec");
|
||||
VTKM_TEST_ASSERT(vec.GetName() == "vec");
|
||||
VTKM_TEST_ASSERT(vec.IsFieldPoint());
|
||||
// Bounds from Information panel:
|
||||
// [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867]
|
||||
const vtkm::cont::ArrayHandle<vtkm::Range>& vecRanges = vec.GetRange();
|
||||
VTKM_TEST_ASSERT(vecRanges.GetNumberOfValues() == 3);
|
||||
auto vecRangesReadPortal = vecRanges.ReadPortal();
|
||||
|
||||
auto xVecRange = vecRangesReadPortal.Get(0);
|
||||
VTKM_TEST_ASSERT(xVecRange.Min >= -65.3148 && xVecRange.Min <= -65.3146);
|
||||
VTKM_TEST_ASSERT(xVecRange.Max >= 86.26 && xVecRange.Min <= 86.268);
|
||||
|
||||
auto yVecRange = vecRangesReadPortal.Get(1);
|
||||
VTKM_TEST_ASSERT(yVecRange.Min >= -88.0326 && yVecRange.Min <= -88.0324);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max >= 78.721);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max <= 78.7218);
|
||||
|
||||
auto zVecRange = vecRangesReadPortal.Get(2);
|
||||
VTKM_TEST_ASSERT(zVecRange.Min >= -67.097 && zVecRange.Min <= -67.096);
|
||||
VTKM_TEST_ASSERT(zVecRange.Max >= 156.866 && zVecRange.Max <= 156.868);
|
||||
}
|
||||
|
||||
void TestReadingDoublePrecisionFishTank()
|
||||
{
|
||||
std::string fishtank = vtkm::cont::testing::Testing::GetTestDataBasePath() +
|
||||
"/rectilinear/fishtank_double_big_endian.vtk";
|
||||
vtkm::cont::DataSet ds = readVTKDataSet(fishtank.c_str());
|
||||
|
||||
// This is information you can glean by running 'strings' on fishtank.vtk:
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().IsType<vtkm::cont::CellSetStructured<3>>(),
|
||||
"Incorrect cellset type");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 50 * 50 * 50, "Incorrect number of points");
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 50 * 50 * 50,
|
||||
"Incorrect number of points (from cell set)");
|
||||
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec"), "The vtk file has a field 'vec', but the dataset does not.");
|
||||
|
||||
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"fishtank has one and only one coordinate system.");
|
||||
// See the single precision version for info:
|
||||
const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem();
|
||||
vtkm::Vec<vtkm::Range, 3> ranges = coordinateSystem.GetRange();
|
||||
vtkm::Range xRange = ranges[0];
|
||||
VTKM_TEST_ASSERT(xRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(xRange.Max == 1);
|
||||
vtkm::Range yRange = ranges[1];
|
||||
VTKM_TEST_ASSERT(yRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(yRange.Max == 1);
|
||||
vtkm::Range zRange = ranges[2];
|
||||
VTKM_TEST_ASSERT(zRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(zRange.Max == 1);
|
||||
|
||||
// This info was gleaned from the Paraview Information panel:
|
||||
const vtkm::cont::Field& vec = ds.GetField("vec");
|
||||
VTKM_TEST_ASSERT(vec.GetName() == "vec");
|
||||
VTKM_TEST_ASSERT(vec.IsFieldPoint());
|
||||
// Bounds from Information panel:
|
||||
// [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867]
|
||||
const vtkm::cont::ArrayHandle<vtkm::Range>& vecRanges = vec.GetRange();
|
||||
VTKM_TEST_ASSERT(vecRanges.GetNumberOfValues() == 3);
|
||||
auto vecRangesReadPortal = vecRanges.ReadPortal();
|
||||
|
||||
auto xVecRange = vecRangesReadPortal.Get(0);
|
||||
VTKM_TEST_ASSERT(xVecRange.Min >= -65.3148 && xVecRange.Min <= -65.3146);
|
||||
VTKM_TEST_ASSERT(xVecRange.Max >= 86.26 && xVecRange.Min <= 86.268);
|
||||
|
||||
auto yVecRange = vecRangesReadPortal.Get(1);
|
||||
VTKM_TEST_ASSERT(yVecRange.Min >= -88.0326 && yVecRange.Min <= -88.0324);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max >= 78.721);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max <= 78.7218);
|
||||
|
||||
auto zVecRange = vecRangesReadPortal.Get(2);
|
||||
VTKM_TEST_ASSERT(zVecRange.Min >= -67.097 && zVecRange.Min <= -67.096);
|
||||
VTKM_TEST_ASSERT(zVecRange.Max >= 156.866 && zVecRange.Max <= 156.868);
|
||||
}
|
||||
|
||||
void TestReadingASCIIFishTank()
|
||||
{
|
||||
std::string fishtank =
|
||||
vtkm::cont::testing::Testing::GetTestDataBasePath() + "/rectilinear/fishtank_double_ascii.vtk";
|
||||
vtkm::cont::DataSet ds = readVTKDataSet(fishtank.c_str());
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().IsType<vtkm::cont::CellSetStructured<3>>(),
|
||||
"Incorrect cellset type");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 50 * 50 * 50, "Incorrect number of points");
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 50 * 50 * 50,
|
||||
"Incorrect number of points (from cell set)");
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec"), "The vtk file has a field 'vec', but the dataset does not.");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"fishtank has one and only one coordinate system.");
|
||||
const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem();
|
||||
vtkm::Vec<vtkm::Range, 3> ranges = coordinateSystem.GetRange();
|
||||
vtkm::Range xRange = ranges[0];
|
||||
VTKM_TEST_ASSERT(xRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(xRange.Max == 1);
|
||||
vtkm::Range yRange = ranges[1];
|
||||
VTKM_TEST_ASSERT(yRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(yRange.Max == 1);
|
||||
vtkm::Range zRange = ranges[2];
|
||||
VTKM_TEST_ASSERT(zRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(zRange.Max == 1);
|
||||
|
||||
const vtkm::cont::Field& vec = ds.GetField("vec");
|
||||
VTKM_TEST_ASSERT(vec.GetName() == "vec");
|
||||
VTKM_TEST_ASSERT(vec.IsFieldPoint());
|
||||
// Bounds from Paraview information panel:
|
||||
// [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867]
|
||||
const vtkm::cont::ArrayHandle<vtkm::Range>& vecRanges = vec.GetRange();
|
||||
VTKM_TEST_ASSERT(vecRanges.GetNumberOfValues() == 3);
|
||||
auto vecRangesReadPortal = vecRanges.ReadPortal();
|
||||
auto xVecRange = vecRangesReadPortal.Get(0);
|
||||
VTKM_TEST_ASSERT(xVecRange.Min >= -65.3148 && xVecRange.Min <= -65.3146);
|
||||
VTKM_TEST_ASSERT(xVecRange.Max >= 86.26 && xVecRange.Min <= 86.268);
|
||||
|
||||
auto yVecRange = vecRangesReadPortal.Get(1);
|
||||
VTKM_TEST_ASSERT(yVecRange.Min >= -88.0326 && yVecRange.Min <= -88.0324);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max >= 78.721);
|
||||
VTKM_TEST_ASSERT(yVecRange.Max <= 78.7218);
|
||||
|
||||
auto zVecRange = vecRangesReadPortal.Get(2);
|
||||
VTKM_TEST_ASSERT(zVecRange.Min >= -67.097 && zVecRange.Min <= -67.096);
|
||||
VTKM_TEST_ASSERT(zVecRange.Max >= 156.866 && zVecRange.Max <= 156.868);
|
||||
}
|
||||
|
||||
void TestReadingFusion()
|
||||
{
|
||||
std::string fusion =
|
||||
vtkm::cont::testing::Testing::GetTestDataBasePath() + "/rectilinear/fusion.vtk";
|
||||
vtkm::cont::DataSet ds = readVTKDataSet(fusion.c_str());
|
||||
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().IsType<vtkm::cont::CellSetStructured<3>>(),
|
||||
"Incorrect cellset type");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 32 * 32 * 32, "Incorrect number of points");
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 32 * 32 * 32,
|
||||
"Incorrect number of points (from cell set)");
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec_magnitude"),
|
||||
"The vtk file has a field 'vec_magnitude', but the dataset does not.");
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec"), "The vtk file has a field 'vec', but the dataset does not.");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"The vtk file has a field 'vec', but the dataset does not.");
|
||||
|
||||
// Taken from Paraview + clicking Data Axes Grid:
|
||||
const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem();
|
||||
vtkm::Vec<vtkm::Range, 3> ranges = coordinateSystem.GetRange();
|
||||
vtkm::Range xRange = ranges[0];
|
||||
VTKM_TEST_ASSERT(xRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(xRange.Max == 1);
|
||||
vtkm::Range yRange = ranges[1];
|
||||
VTKM_TEST_ASSERT(yRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(yRange.Max == 1);
|
||||
vtkm::Range zRange = ranges[2];
|
||||
VTKM_TEST_ASSERT(zRange.Min == 0);
|
||||
VTKM_TEST_ASSERT(zRange.Max == 1);
|
||||
|
||||
// Paraview Information Panel of this file:
|
||||
// vec_magnitude [0, 3.73778]
|
||||
vtkm::cont::Field vec_magnitude = ds.GetField("vec_magnitude");
|
||||
VTKM_TEST_ASSERT(vec_magnitude.GetName() == "vec_magnitude");
|
||||
VTKM_TEST_ASSERT(vec_magnitude.IsFieldPoint());
|
||||
|
||||
vtkm::Range mag_range;
|
||||
vec_magnitude.GetRange(&mag_range);
|
||||
VTKM_TEST_ASSERT(mag_range.Min == 0);
|
||||
VTKM_TEST_ASSERT(mag_range.Max <= 3.73779);
|
||||
VTKM_TEST_ASSERT(mag_range.Max >= 3.73777);
|
||||
|
||||
vtkm::cont::Field vec = ds.GetField("vec");
|
||||
VTKM_TEST_ASSERT(vec.GetName() == "vec");
|
||||
VTKM_TEST_ASSERT(vec.IsFieldPoint());
|
||||
const vtkm::cont::ArrayHandle<vtkm::Range>& vecRanges = vec.GetRange();
|
||||
VTKM_TEST_ASSERT(vecRanges.GetNumberOfValues() == 3);
|
||||
auto vecRangesReadPortal = vecRanges.ReadPortal();
|
||||
|
||||
// vec float [-3.41054, 3.40824], [-3.41018, 3.41036], [-0.689022, 0.480726]
|
||||
auto xVecRange = vecRangesReadPortal.Get(0);
|
||||
VTKM_TEST_ASSERT(test_equal(xVecRange.Min, -3.41054));
|
||||
VTKM_TEST_ASSERT(test_equal(xVecRange.Max, 3.40824));
|
||||
|
||||
auto yVecRange = vecRangesReadPortal.Get(1);
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal(yVecRange.Min, -3.41018));
|
||||
VTKM_TEST_ASSERT(test_equal(yVecRange.Max, 3.41036));
|
||||
|
||||
auto zVecRange = vecRangesReadPortal.Get(2);
|
||||
VTKM_TEST_ASSERT(test_equal(zVecRange.Min, -0.689022));
|
||||
VTKM_TEST_ASSERT(test_equal(zVecRange.Max, 0.480726));
|
||||
}
|
||||
|
||||
void TestReadingVTKDataSet()
|
||||
{
|
||||
std::cout << "Test reading VTK Polydata file in ASCII" << std::endl;
|
||||
@ -607,6 +855,14 @@ void TestReadingVTKDataSet()
|
||||
TestReadingStructuredGridASCII();
|
||||
std::cout << "Test reading VTK StructuredGrid file in BINARY" << std::endl;
|
||||
TestReadingStructuredGridBin();
|
||||
std::cout << "Test reading float precision fishtank" << std::endl;
|
||||
TestReadingFishTank();
|
||||
std::cout << "Test reading double precision fishtank" << std::endl;
|
||||
TestReadingDoublePrecisionFishTank();
|
||||
std::cout << "Test ASCII fishtank" << std::endl;
|
||||
TestReadingASCIIFishTank();
|
||||
std::cout << "Test reading fusion" << std::endl;
|
||||
TestReadingFusion();
|
||||
}
|
||||
|
||||
int UnitTestVTKDataSetReader(int argc, char* argv[])
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef vtk_m_rendering_Mapper_h
|
||||
#define vtk_m_rendering_Mapper_h
|
||||
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/cont/ColorTable.h>
|
||||
#include <vtkm/cont/CoordinateSystem.h>
|
||||
#include <vtkm/cont/DynamicCellSet.h>
|
||||
@ -38,8 +39,12 @@ public:
|
||||
|
||||
virtual void SetActiveColorTable(const vtkm::cont::ColorTable& ct);
|
||||
|
||||
virtual void StartScene() = 0;
|
||||
virtual void EndScene() = 0;
|
||||
VTKM_DEPRECATED(1.6, "StartScene() does nothing")
|
||||
void StartScene() {}
|
||||
|
||||
VTKM_DEPRECATED(1.6, "EndScene() does nothing")
|
||||
void EndScene() {}
|
||||
|
||||
virtual void SetCanvas(vtkm::rendering::Canvas* canvas) = 0;
|
||||
virtual vtkm::rendering::Canvas* GetCanvas() const = 0;
|
||||
|
||||
|
@ -85,16 +85,6 @@ void MapperConnectivity::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
|
||||
tracerProxy.Trace(camera, CanvasRT);
|
||||
}
|
||||
|
||||
void MapperConnectivity::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperConnectivity::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperConnectivity::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperConnectivity(*this);
|
||||
|
@ -37,9 +37,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
void CreateDefaultView();
|
||||
|
||||
|
@ -217,16 +217,6 @@ void MapperCylinder::SetCompositeBackground(bool on)
|
||||
this->Internals->CompositeBackground = on;
|
||||
}
|
||||
|
||||
void MapperCylinder::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperCylinder::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperCylinder::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperCylinder(*this);
|
||||
|
@ -68,8 +68,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
void SetCompositeBackground(bool on);
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
|
||||
|
@ -216,16 +216,6 @@ void MapperPoint::SetCompositeBackground(bool on)
|
||||
this->Internals->CompositeBackground = on;
|
||||
}
|
||||
|
||||
void MapperPoint::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperPoint::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperPoint::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperPoint(*this);
|
||||
|
@ -79,8 +79,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
void SetCompositeBackground(bool on);
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
|
||||
|
@ -138,16 +138,6 @@ void MapperQuad::SetCompositeBackground(bool on)
|
||||
this->Internals->CompositeBackground = on;
|
||||
}
|
||||
|
||||
void MapperQuad::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperQuad::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperQuad::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperQuad(*this);
|
||||
|
@ -44,8 +44,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
void SetCompositeBackground(bool on);
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
|
||||
|
@ -151,16 +151,6 @@ void MapperRayTracer::SetShadingOn(bool on)
|
||||
this->Internals->Shade = on;
|
||||
}
|
||||
|
||||
void MapperRayTracer::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperRayTracer::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperRayTracer::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperRayTracer(*this);
|
||||
|
@ -38,8 +38,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
void SetCompositeBackground(bool on);
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
void SetShadingOn(bool on);
|
||||
|
@ -137,16 +137,6 @@ void MapperVolume::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
|
||||
}
|
||||
}
|
||||
|
||||
void MapperVolume::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperVolume::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
vtkm::rendering::Mapper* MapperVolume::NewCopy() const
|
||||
{
|
||||
return new vtkm::rendering::MapperVolume(*this);
|
||||
|
@ -36,9 +36,6 @@ public:
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::Range& scalarRange) override;
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
|
||||
vtkm::rendering::Mapper* NewCopy() const override;
|
||||
void SetSampleDistance(const vtkm::Float32 distance);
|
||||
void SetCompositeBackground(const bool compositeBackground);
|
||||
|
@ -231,16 +231,6 @@ void MapperWireframer::SetIsOverlay(bool isOverlay)
|
||||
this->Internals->IsOverlay = isOverlay;
|
||||
}
|
||||
|
||||
void MapperWireframer::StartScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperWireframer::EndScene()
|
||||
{
|
||||
// Nothing needs to be done.
|
||||
}
|
||||
|
||||
void MapperWireframer::RenderCells(const vtkm::cont::DynamicCellSet& inCellSet,
|
||||
const vtkm::cont::CoordinateSystem& coords,
|
||||
const vtkm::cont::Field& inScalarField,
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
bool GetIsOverlay() const;
|
||||
void SetIsOverlay(bool isOverlay);
|
||||
|
||||
virtual void StartScene() override;
|
||||
virtual void EndScene() override;
|
||||
|
||||
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
|
||||
const vtkm::cont::CoordinateSystem& coords,
|
||||
const vtkm::cont::Field& scalarField,
|
||||
|
@ -46,13 +46,11 @@ void Scene::Render(vtkm::rendering::Mapper& mapper,
|
||||
vtkm::rendering::Canvas& canvas,
|
||||
const vtkm::rendering::Camera& camera) const
|
||||
{
|
||||
mapper.StartScene();
|
||||
for (vtkm::IdComponent actorIndex = 0; actorIndex < this->GetNumberOfActors(); actorIndex++)
|
||||
{
|
||||
const vtkm::rendering::Actor& actor = this->GetActor(actorIndex);
|
||||
actor.Render(mapper, canvas, camera);
|
||||
}
|
||||
mapper.EndScene();
|
||||
}
|
||||
|
||||
vtkm::Bounds Scene::GetSpatialBounds() const
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vtkm/rendering/raytracing/ChannelBufferOperations.h>
|
||||
#include <vtkm/rendering/raytracing/Ray.h>
|
||||
#include <vtkm/rendering/raytracing/Worklets.h>
|
||||
#include <vtkm/rendering/vtkm_rendering_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -132,9 +133,9 @@ public:
|
||||
dispatcher.Invoke(rays.HitIdx, rays.Status);
|
||||
}
|
||||
|
||||
static void MapCanvasToRays(Ray<vtkm::Float32>& rays,
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::rendering::CanvasRayTracer& canvas);
|
||||
VTKM_RENDERING_EXPORT static void MapCanvasToRays(Ray<vtkm::Float32>& rays,
|
||||
const vtkm::rendering::Camera& camera,
|
||||
const vtkm::rendering::CanvasRayTracer& canvas);
|
||||
|
||||
template <typename T>
|
||||
static vtkm::Id RaysInMesh(Ray<T>& rays)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
|
||||
#include <vtkm/rendering/raytracing/Ray.h>
|
||||
#include <vtkm/rendering/vtkm_rendering_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -21,7 +22,7 @@ namespace rendering
|
||||
namespace raytracing
|
||||
{
|
||||
|
||||
class VolumeRendererStructured
|
||||
class VTKM_RENDERING_EXPORT VolumeRendererStructured
|
||||
{
|
||||
public:
|
||||
using DefaultHandle = vtkm::cont::ArrayHandle<vtkm::FloatDefault>;
|
||||
|
@ -405,6 +405,7 @@ public:
|
||||
catch (std::exception& error)
|
||||
{
|
||||
std::cout << "***** STL exception throw." << std::endl << error.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -646,6 +646,264 @@ struct ScalarVectorFieldTests : public vtkm::exec::FunctorBase
|
||||
"CopySign failed.");
|
||||
}
|
||||
|
||||
VTKM_EXEC
|
||||
void TestFloatDistance() const
|
||||
{
|
||||
{
|
||||
vtkm::UInt64 dist = vtkm::FloatDistance(1.0, 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 1.0 to 1.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-1.0, -1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -1.0 to -1.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(0.0, 0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 0.0 to 0.0 is not zero.");
|
||||
|
||||
// Check nan:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::quiet_NaN(), 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to a Nan is not the documented value.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0, std::numeric_limits<vtkm::Float64>::quiet_NaN());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to a Nan is not the documented value.");
|
||||
|
||||
// Check infinity:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::infinity(), 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to infinity is not the documented value.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0, std::numeric_limits<vtkm::Float64>::infinity());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to infinity is not the documented value.");
|
||||
|
||||
// Check saturation:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::lowest(),
|
||||
std::numeric_limits<vtkm::Float64>::max());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist),
|
||||
"Float distance from lowest to max is incorrect.");
|
||||
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::max(),
|
||||
std::numeric_limits<vtkm::Float64>::lowest());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist),
|
||||
"Float distance from max to lowest is incorrect.");
|
||||
|
||||
// Check symmetry:
|
||||
dist = vtkm::FloatDistance(-2.0, -1.0);
|
||||
vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0, -2.0);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0, 2.0);
|
||||
dist2 = vtkm::FloatDistance(2.0, 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1.");
|
||||
|
||||
// Check symmetry of bound which includes zero:
|
||||
dist = vtkm::FloatDistance(-0.25, 0.25);
|
||||
dist2 = vtkm::FloatDistance(0.25, -0.25);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist),
|
||||
"Symmetry is violated over a bound which contains zero.");
|
||||
|
||||
// Check correctness:
|
||||
dist = vtkm::FloatDistance(1.0, 1.0 + std::numeric_limits<vtkm::Float64>::epsilon());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Float distance from 1 to 1 + eps is not = 1.");
|
||||
dist = vtkm::FloatDistance(1.0 + std::numeric_limits<vtkm::Float64>::epsilon(), 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0, 1.0 + 2 * std::numeric_limits<vtkm::Float64>::epsilon());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist),
|
||||
"Float distance from 1 to 1 + 2eps is not 2.");
|
||||
dist = vtkm::FloatDistance(1.0 + 2 * std::numeric_limits<vtkm::Float64>::epsilon(), 1.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist), "Symmetry is violated.");
|
||||
|
||||
// Now test x = y:
|
||||
vtkm::Float64 x = -1;
|
||||
for (int i = 0; i < 500; ++i)
|
||||
{
|
||||
dist = vtkm::FloatDistance(x, x);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from x to x is not zero.");
|
||||
x += 0.01;
|
||||
}
|
||||
// Test zero:
|
||||
dist = vtkm::FloatDistance(0.0, 0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from zero to zero is not zero.");
|
||||
// Test signed zero:
|
||||
dist = vtkm::FloatDistance(0.0, -0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 0.0 to -0.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-0.0, 0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -0.0 to 0.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-0.0, -0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -0.0 to 0.0 is not zero.");
|
||||
|
||||
// Negative to negative zero:
|
||||
dist = vtkm::FloatDistance(-std::numeric_limits<vtkm::Float64>::denorm_min(), -0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(-0.0, -std::numeric_limits<vtkm::Float64>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
|
||||
// Negative to positive zero:
|
||||
dist = vtkm::FloatDistance(-std::numeric_limits<vtkm::Float64>::denorm_min(), 0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Negative to positive zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(0.0, -std::numeric_limits<vtkm::Float64>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
|
||||
// Positive to zero:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::denorm_min(), 0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(0.0, std::numeric_limits<vtkm::Float64>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated");
|
||||
|
||||
// Positive to negative zero:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float64>::denorm_min(), -0.0);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Positive to negative zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(-0.0, std::numeric_limits<vtkm::Float64>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
}
|
||||
|
||||
// I would try to just template these, but in fact the double precision version has to saturate,
|
||||
// whereas the float version has sufficient range.
|
||||
{
|
||||
vtkm::UInt64 dist = vtkm::FloatDistance(1.0f, 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 1.0 to 1.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-1.0f, -1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -1.0 to -1.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(0.0f, 0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 0.0 to 0.0 is not zero.");
|
||||
|
||||
// Check nan:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::quiet_NaN(), 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to a Nan is not the documented value.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0f, std::numeric_limits<vtkm::Float32>::quiet_NaN());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to a Nan is not the documented value.");
|
||||
|
||||
// Check infinity:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::infinity(), 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to infinity is not the documented value.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0f, std::numeric_limits<vtkm::Float32>::infinity());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist),
|
||||
"Float distance to infinity is not the documented value.");
|
||||
|
||||
// Check saturation:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::lowest(),
|
||||
std::numeric_limits<vtkm::Float32>::max());
|
||||
VTKM_MATH_ASSERT(dist > 0, "Float distance is negative.");
|
||||
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::max(),
|
||||
std::numeric_limits<vtkm::Float32>::lowest());
|
||||
VTKM_MATH_ASSERT(dist > 0, "Float distance is negative.");
|
||||
|
||||
// Check symmetry:
|
||||
dist = vtkm::FloatDistance(-2.0f, -1.0f);
|
||||
vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0f, -2.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold.");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0f, 2.0f);
|
||||
dist2 = vtkm::FloatDistance(2.0f, 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1.");
|
||||
|
||||
// Check symmetry of bound which includes zero:
|
||||
dist = vtkm::FloatDistance(-0.25f, 0.25f);
|
||||
dist2 = vtkm::FloatDistance(0.25f, -0.25f);
|
||||
VTKM_MATH_ASSERT(test_equal(dist2, dist),
|
||||
"Symmetry is violated over a bound which contains zero.");
|
||||
|
||||
// Check correctness:
|
||||
dist = vtkm::FloatDistance(1.0f, 1.0f + std::numeric_limits<vtkm::Float32>::epsilon());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Float distance from 1 to 1 + eps is not = 1.");
|
||||
dist = vtkm::FloatDistance(1.0f + std::numeric_limits<vtkm::Float32>::epsilon(), 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated");
|
||||
|
||||
dist = vtkm::FloatDistance(1.0f, 1.0f + 2 * std::numeric_limits<vtkm::Float32>::epsilon());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist),
|
||||
"Float distance from 1 to 1 + 2eps is not 2.");
|
||||
dist = vtkm::FloatDistance(1.0f + 2 * std::numeric_limits<vtkm::Float32>::epsilon(), 1.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist), "Symmetry is violated.");
|
||||
|
||||
// Now test x = y:
|
||||
vtkm::Float32 x = -1;
|
||||
for (int i = 0; i < 500; ++i)
|
||||
{
|
||||
dist = vtkm::FloatDistance(x, x);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from x to x is not zero.");
|
||||
x += 0.01f;
|
||||
}
|
||||
// Test zero:
|
||||
dist = vtkm::FloatDistance(0.0f, 0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from zero to zero is not zero.");
|
||||
// Test signed zero:
|
||||
dist = vtkm::FloatDistance(0.0f, -0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from 0.0 to -0.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-0.0f, 0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -0.0 to 0.0 is not zero.");
|
||||
|
||||
dist = vtkm::FloatDistance(-0.0f, -0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist),
|
||||
"Float distance from -0.0 to 0.0 is not zero.");
|
||||
|
||||
// Negative to negative zero:
|
||||
dist = vtkm::FloatDistance(-std::numeric_limits<vtkm::Float32>::denorm_min(), -0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(-0.0f, -std::numeric_limits<vtkm::Float32>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
|
||||
// Negative to positive zero:
|
||||
dist = vtkm::FloatDistance(-std::numeric_limits<vtkm::Float32>::denorm_min(), 0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Negative to positive zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(0.0f, -std::numeric_limits<vtkm::Float32>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
|
||||
// Positive to zero:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::denorm_min(), 0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(0.0f, std::numeric_limits<vtkm::Float32>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated");
|
||||
|
||||
// Positive to negative zero:
|
||||
dist = vtkm::FloatDistance(std::numeric_limits<vtkm::Float32>::denorm_min(), -0.0f);
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist),
|
||||
"Positive to negative zero is incorrect.");
|
||||
// And symmetry:
|
||||
dist = vtkm::FloatDistance(-0.0f, std::numeric_limits<vtkm::Float32>::denorm_min());
|
||||
VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated.");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_EXEC
|
||||
void operator()(vtkm::Id) const
|
||||
{
|
||||
@ -663,6 +921,7 @@ struct ScalarVectorFieldTests : public vtkm::exec::FunctorBase
|
||||
this->TestLog10();
|
||||
this->TestLog1P();
|
||||
this->TestCopySign();
|
||||
this->TestFloatDistance();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -97,38 +97,38 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T N() const { return this->n_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Min() const { return this->min_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Max() const { return this->max_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Sum() const { return this->sum_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Mean() const { return this->mean_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T SampleStddev() const { return vtkm::Sqrt(this->SampleVariance()); }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T PopulationStddev() const { return vtkm::Sqrt(this->PopulationVariance()); }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T SampleVariance() const
|
||||
{
|
||||
VTKM_ASSERT(n_ != 1);
|
||||
return this->M2_ / (this->n_ - 1);
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T PopulationVariance() const { return this->M2_ / this->n_; }
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Skewness() const
|
||||
{
|
||||
if (this->M2_ == 0)
|
||||
@ -140,7 +140,7 @@ public:
|
||||
return vtkm::Sqrt(this->n_) * this->M3_ / vtkm::Pow(this->M2_, T{ 1.5 });
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
VTKM_EXEC_CONT
|
||||
T Kurtosis() const
|
||||
{
|
||||
if (this->M2_ == 0)
|
||||
|
@ -227,7 +227,7 @@ public:
|
||||
return SortIndicesPortal.Get(meshIndex + (this->NumRows * this->NumColumns) +
|
||||
this->NumColumns + 1); // { 1, 1, 1 }
|
||||
default:
|
||||
VTKM_ASSERT(false);
|
||||
assert(false);
|
||||
return meshIndex; // Need to error out here
|
||||
}
|
||||
} // GetNeighbourIndex
|
||||
|
@ -90,7 +90,7 @@ set(unit_tests
|
||||
|
||||
vtkm_unit_tests(
|
||||
SOURCES ${unit_tests}
|
||||
LIBRARIES vtkm_source vtkm_worklet vtkm_filter
|
||||
LIBRARIES vtkm_source vtkm_worklet vtkm_filter vtkm_io
|
||||
ALL_BACKENDS
|
||||
USE_VTKM_JOB_POOL
|
||||
)
|
||||
|
@ -19,13 +19,13 @@ void TestSingle()
|
||||
auto single_array = vtkm::cont::make_ArrayHandle(single);
|
||||
auto result = vtkm::worklet::DescriptiveStatistics::Run(single_array);
|
||||
|
||||
VTKM_TEST_ASSERT(result.N() == 1);
|
||||
VTKM_TEST_ASSERT(result.Mean() == 42);
|
||||
VTKM_TEST_ASSERT(result.PopulationVariance() == 0);
|
||||
VTKM_TEST_ASSERT(test_equal(result.N(), 1));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Mean(), 42));
|
||||
VTKM_TEST_ASSERT(test_equal(result.PopulationVariance(), 0));
|
||||
|
||||
// A single number does not have skewness nor kurtosis
|
||||
VTKM_TEST_ASSERT(result.Skewness() == 0);
|
||||
VTKM_TEST_ASSERT(result.Kurtosis() == 0);
|
||||
VTKM_TEST_ASSERT(test_equal(result.Skewness(), 0));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Kurtosis(), 0));
|
||||
}
|
||||
|
||||
void TestConstant()
|
||||
@ -33,11 +33,11 @@ void TestConstant()
|
||||
auto constants = vtkm::cont::make_ArrayHandleConstant(1234.f, 10000);
|
||||
auto result = vtkm::worklet::DescriptiveStatistics::Run(constants);
|
||||
|
||||
VTKM_TEST_ASSERT(result.N() == 10000);
|
||||
VTKM_TEST_ASSERT(result.Sum() == 12340000);
|
||||
VTKM_TEST_ASSERT(result.PopulationVariance() == 0);
|
||||
VTKM_TEST_ASSERT(result.Skewness() == 0);
|
||||
VTKM_TEST_ASSERT(result.Kurtosis() == 0);
|
||||
VTKM_TEST_ASSERT(test_equal(result.N(), 10000));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Sum(), 12340000));
|
||||
VTKM_TEST_ASSERT(test_equal(result.PopulationVariance(), 0));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Skewness(), 0));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Kurtosis(), 0));
|
||||
}
|
||||
|
||||
void TestIntegerSequence()
|
||||
@ -45,11 +45,12 @@ void TestIntegerSequence()
|
||||
// We only have 23 bits for FloatInt in Float32. This limits N to 11 bits.
|
||||
constexpr vtkm::Float32 N = 1000;
|
||||
|
||||
auto integers = vtkm::cont::ArrayHandleCounting<vtkm::Float32>(0.0f, 1.0f, N);
|
||||
auto integers =
|
||||
vtkm::cont::ArrayHandleCounting<vtkm::Float32>(0.0f, 1.0f, static_cast<vtkm::Id>(N));
|
||||
auto result = vtkm::worklet::DescriptiveStatistics::Run(integers);
|
||||
|
||||
VTKM_TEST_ASSERT(result.N() == N);
|
||||
VTKM_TEST_ASSERT(result.Sum() == N * (N - 1) / 2);
|
||||
VTKM_TEST_ASSERT(test_equal(result.N(), N));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Sum(), N * (N - 1) / 2));
|
||||
VTKM_TEST_ASSERT(test_equal(result.Mean(), (N - 1) / 2));
|
||||
|
||||
// Expected values are from Numpy/SciPy
|
||||
@ -87,10 +88,10 @@ void TestCatastrophicCancellation()
|
||||
auto arrayOK = vtkm::cont::make_ArrayHandle(okay);
|
||||
auto resultOK = vtkm::worklet::DescriptiveStatistics::Run(arrayOK);
|
||||
|
||||
VTKM_TEST_ASSERT(resultOK.N() == 4);
|
||||
VTKM_TEST_ASSERT(resultOK.Sum() == 4.0e8 + 40);
|
||||
VTKM_TEST_ASSERT(resultOK.Min() == 1.0e8 + 4);
|
||||
VTKM_TEST_ASSERT(resultOK.Max() == 1.0e8 + 16);
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.N(), 4));
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.Sum(), 4.0e8 + 40));
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.Min(), 1.0e8 + 4));
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.Max(), 1.0e8 + 16));
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.SampleVariance(), 30));
|
||||
VTKM_TEST_ASSERT(test_equal(resultOK.PopulationVariance(), 22.5));
|
||||
|
||||
@ -100,10 +101,10 @@ void TestCatastrophicCancellation()
|
||||
auto arrayEvil = vtkm::cont::make_ArrayHandle(evil);
|
||||
auto resultEvil = vtkm::worklet::DescriptiveStatistics::Run(arrayEvil);
|
||||
|
||||
VTKM_TEST_ASSERT(resultEvil.N() == 4);
|
||||
VTKM_TEST_ASSERT(resultEvil.Sum() == 4.0e9 + 40);
|
||||
VTKM_TEST_ASSERT(resultEvil.Min() == 1.0e9 + 4);
|
||||
VTKM_TEST_ASSERT(resultEvil.Max() == 1.0e9 + 16);
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.N(), 4));
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.Sum(), 4.0e9 + 40));
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.Min(), 1.0e9 + 4));
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.Max(), 1.0e9 + 16));
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.SampleVariance(), 30));
|
||||
VTKM_TEST_ASSERT(test_equal(resultEvil.PopulationVariance(), 22.5));
|
||||
}
|
||||
@ -220,7 +221,8 @@ void TestMomentsByKey()
|
||||
{
|
||||
std::vector<vtkm::UInt32> keys{ 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 };
|
||||
|
||||
auto values_array = vtkm::cont::make_ArrayHandleConstant(1.0f, keys.size());
|
||||
auto values_array =
|
||||
vtkm::cont::make_ArrayHandleConstant(1.0f, static_cast<vtkm::Id>(keys.size()));
|
||||
auto keys_array = vtkm::cont::make_ArrayHandle(keys);
|
||||
|
||||
auto results = vtkm::worklet::DescriptiveStatistics::Run(keys_array, values_array);
|
||||
@ -234,9 +236,9 @@ void TestMomentsByKey()
|
||||
for (vtkm::Id i = 0; i < results.GetNumberOfValues(); ++i)
|
||||
{
|
||||
auto result = resultsPortal.Get(i);
|
||||
VTKM_TEST_ASSERT(result.first == i);
|
||||
VTKM_TEST_ASSERT(result.second.N() == expected_ns[i]);
|
||||
VTKM_TEST_ASSERT(result.second.PopulationVariance() == 0);
|
||||
VTKM_TEST_ASSERT(test_equal(result.first, i));
|
||||
VTKM_TEST_ASSERT(test_equal(result.second.N(), expected_ns[static_cast<std::size_t>(i)]));
|
||||
VTKM_TEST_ASSERT(test_equal(result.second.PopulationVariance(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vtkm/cont/DataSetBuilderRectilinear.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/io/VTKDataSetReader.h>
|
||||
#include <vtkm/worklet/ParticleAdvection.h>
|
||||
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
|
||||
#include <vtkm/worklet/particleadvection/Integrators.h>
|
||||
@ -847,6 +848,103 @@ void TestWorkletsBasic()
|
||||
}
|
||||
}
|
||||
|
||||
template <class ResultType>
|
||||
void ValidateResult(const ResultType& res,
|
||||
vtkm::Id maxSteps,
|
||||
const std::vector<vtkm::Vec3f>& endPts)
|
||||
{
|
||||
const vtkm::FloatDefault eps = static_cast<vtkm::FloatDefault>(1e-3);
|
||||
vtkm::Id numPts = static_cast<vtkm::Id>(endPts.size());
|
||||
|
||||
VTKM_TEST_ASSERT(res.Particles.GetNumberOfValues() == numPts,
|
||||
"Wrong number of points in particle advection result.");
|
||||
|
||||
auto portal = res.Particles.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < 3; i++)
|
||||
{
|
||||
vtkm::Vec3f p = portal.Get(i).Pos;
|
||||
vtkm::Vec3f e = endPts[static_cast<std::size_t>(i)];
|
||||
|
||||
VTKM_TEST_ASSERT(vtkm::Magnitude(p - e) <= eps, "Particle advection point is wrong");
|
||||
VTKM_TEST_ASSERT(portal.Get(i).NumSteps == maxSteps, "Particle advection NumSteps is wrong");
|
||||
VTKM_TEST_ASSERT(portal.Get(i).Status.CheckOk(), "Particle advection Status is wrong");
|
||||
VTKM_TEST_ASSERT(portal.Get(i).Status.CheckTerminate(),
|
||||
"Particle advection particle did not terminate");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestParticleAdvectionFile(const std::string& fname,
|
||||
const std::vector<vtkm::Vec3f>& pts,
|
||||
vtkm::FloatDefault stepSize,
|
||||
vtkm::Id maxSteps,
|
||||
const std::vector<vtkm::Vec3f>& endPts)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing particle advection on file " << fname);
|
||||
vtkm::io::VTKDataSetReader reader(fname);
|
||||
vtkm::cont::DataSet ds;
|
||||
try
|
||||
{
|
||||
ds = reader.ReadDataSet();
|
||||
}
|
||||
catch (vtkm::io::ErrorIO& e)
|
||||
{
|
||||
std::string message("Error reading: ");
|
||||
message += fname;
|
||||
message += ", ";
|
||||
message += e.GetMessage();
|
||||
|
||||
VTKM_TEST_FAIL(message.c_str());
|
||||
}
|
||||
|
||||
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f_32>;
|
||||
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
|
||||
VTKM_TEST_ASSERT(ds.HasField("vec"));
|
||||
vtkm::cont::Field& field = ds.GetField("vec");
|
||||
auto fieldData = field.GetData();
|
||||
|
||||
if (!fieldData.IsType<FieldHandle>())
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
|
||||
"The field data is of type "
|
||||
<< vtkm::cont::TypeToString<decltype(fieldData)>()
|
||||
<< ", but we expect type vtkm::cont::ArrayHandle<vtkm::Vec3f>");
|
||||
VTKM_TEST_FAIL("No field with correct type found.");
|
||||
}
|
||||
|
||||
|
||||
FieldHandle fieldArray = fieldData.Cast<FieldHandle>();
|
||||
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), fieldArray);
|
||||
RK4Type rk4(eval, stepSize);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
std::vector<vtkm::Particle> seeds;
|
||||
for (size_t j = 0; j < pts.size(); j++)
|
||||
seeds.push_back(vtkm::Particle(pts[j], static_cast<vtkm::Id>(j)));
|
||||
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
vtkm::worklet::ParticleAdvection pa;
|
||||
vtkm::worklet::ParticleAdvectionResult res;
|
||||
|
||||
res = pa.Run(rk4, seedArray, maxSteps);
|
||||
ValidateResult(res, maxSteps, endPts);
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
vtkm::worklet::Streamline s;
|
||||
vtkm::worklet::StreamlineResult res;
|
||||
|
||||
res = s.Run(rk4, seedArray, maxSteps);
|
||||
ValidateResult(res, maxSteps, endPts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestParticleAdvection()
|
||||
{
|
||||
TestIntegrators();
|
||||
@ -854,6 +952,35 @@ void TestParticleAdvection()
|
||||
TestParticleStatus();
|
||||
TestWorkletsBasic();
|
||||
TestParticleWorkletsWithDataSetTypes();
|
||||
|
||||
std::string basePath = vtkm::cont::testing::Testing::GetTestDataBasePath();
|
||||
|
||||
//Fusion test.
|
||||
std::vector<vtkm::Vec3f> fusionPts, fusionEndPts;
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.6f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.6f));
|
||||
fusionPts.push_back(vtkm::Vec3f(0.8f, 0.8f, 0.3f));
|
||||
//End point values were generated in VisIt.
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5335789918f, 0.87112802267f, 0.6723330020f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.5601879954f, 0.91389900446f, 0.43989110522f));
|
||||
fusionEndPts.push_back(vtkm::Vec3f(0.7004770041f, 0.63193398714f, 0.64524400234f));
|
||||
vtkm::FloatDefault fusionStep = 0.005f;
|
||||
std::string fusionFile = basePath + "/rectilinear/fusion.vtk";
|
||||
TestParticleAdvectionFile(fusionFile, fusionPts, fusionStep, 1000, fusionEndPts);
|
||||
|
||||
//Fishtank test.
|
||||
std::vector<vtkm::Vec3f> fishPts, fishEndPts;
|
||||
fishPts.push_back(vtkm::Vec3f(0.75f, 0.5f, 0.01f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.4f, 0.2f, 0.7f));
|
||||
fishPts.push_back(vtkm::Vec3f(0.5f, 0.3f, 0.8f));
|
||||
//End point values were generated in VisIt.
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7734669447f, 0.4870159328f, 0.8979591727f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.7257543206f, 0.1277695596f, 0.7468645573f));
|
||||
fishEndPts.push_back(vtkm::Vec3f(0.8347796798f, 0.1276152730f, 0.4985143244f));
|
||||
|
||||
vtkm::FloatDefault fishStep = 0.001f;
|
||||
std::string fishFile = basePath + "/rectilinear/fishtank.vtk";
|
||||
TestParticleAdvectionFile(fishFile, fishPts, fishStep, 100, fishEndPts);
|
||||
}
|
||||
|
||||
int UnitTestParticleAdvection(int argc, char* argv[])
|
||||
|
Loading…
Reference in New Issue
Block a user