From 934732bb642f20b52362cc195c63417f45ebcc4d Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 3 Feb 2020 11:00:31 -0700 Subject: [PATCH] Add MapFieldPermutation function This function is compiled into the vtkm_filter library, so all filters can implement this type of mapping without providing their own version of compiling it. Because we only compile it once, we provide more types to convert. Hopefully the total compile time balances out. --- vtkm/filter/CMakeLists.txt | 2 + vtkm/filter/MapFieldPermutation.cxx | 73 +++++++++++ vtkm/filter/MapFieldPermutation.h | 72 +++++++++++ vtkm/filter/testing/CMakeLists.txt | 1 + .../testing/UnitTestMapFieldPermutation.cxx | 114 ++++++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 vtkm/filter/MapFieldPermutation.cxx create mode 100644 vtkm/filter/MapFieldPermutation.h create mode 100644 vtkm/filter/testing/UnitTestMapFieldPermutation.cxx diff --git a/vtkm/filter/CMakeLists.txt b/vtkm/filter/CMakeLists.txt index 631314d61..2b56dc0d3 100644 --- a/vtkm/filter/CMakeLists.txt +++ b/vtkm/filter/CMakeLists.txt @@ -45,6 +45,7 @@ set(headers ImageMedian.h Lagrangian.h LagrangianStructures.h + MapFieldPermutation.h Mask.h MaskPoints.h MeshQuality.h @@ -154,6 +155,7 @@ set(sources_device GradientScalar.cxx GradientUniformPoints.cxx GradientVector.cxx + MapFieldPermutation.cxx PointAverage.cxx Threshold.cxx VectorMagnitude.cxx diff --git a/vtkm/filter/MapFieldPermutation.cxx b/vtkm/filter/MapFieldPermutation.cxx new file mode 100644 index 000000000..ac3f24b5a --- /dev/null +++ b/vtkm/filter/MapFieldPermutation.cxx @@ -0,0 +1,73 @@ +//============================================================================ +// 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 + +#include + +#include +#include +#include + +#include + +namespace +{ + +struct DoMapFieldPermutation +{ + bool CalledMap = false; + + template + void operator()(const vtkm::cont::ArrayHandle& inputArray, + const vtkm::cont::ArrayHandle& permutation, + vtkm::cont::VariantArrayHandle& output) + { + vtkm::cont::ArrayHandle outputArray; + vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandlePermutation(permutation, inputArray), + outputArray); + output = vtkm::cont::VariantArrayHandle(outputArray); + this->CalledMap = true; + } +}; + +} // anonymous namespace + +bool vtkm::filter::MapFieldPermutation(const vtkm::cont::Field& inputField, + const vtkm::cont::ArrayHandle& permutation, + vtkm::cont::Field& outputField) +{ + vtkm::cont::VariantArrayHandle outputArray; + DoMapFieldPermutation functor; + inputField.GetData().ResetTypes().CastAndCall( + vtkm::filter::PolicyDefault::StorageList{}, functor, permutation, outputArray); + if (functor.CalledMap) + { + outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray); + } + else + { + VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Faild to map field " << inputField.GetName()); + } + return functor.CalledMap; +} + +bool MapFieldPermutation(const vtkm::cont::Field& inputField, + const vtkm::cont::ArrayHandle& permutation, + vtkm::cont::DataSet& outputData) +{ + vtkm::cont::Field outputField; + bool success = vtkm::filter::MapFieldPermutation(inputField, permutation, outputField); + if (success) + { + outputData.AddField(outputField); + } + return success; +} diff --git a/vtkm/filter/MapFieldPermutation.h b/vtkm/filter/MapFieldPermutation.h new file mode 100644 index 000000000..cd62d17d5 --- /dev/null +++ b/vtkm/filter/MapFieldPermutation.h @@ -0,0 +1,72 @@ +//============================================================================ +// 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_MapFieldPermutation_h +#define vtk_m_filter_MapFieldPermutation_h + +#include +#include +#include + +#include + +namespace vtkm +{ +namespace filter +{ + +/// \brief Maps a field by permuting it by a given index array. +/// +/// This method will create a new field containing the data from the provided `inputField` but +/// reorded by the given `permutation` index array. The value in the resulting field for index _i_ +/// will be be a value from `inputField`, but comes from the index that comes from `permutation` at +/// position _i_. The result is placed in `outputField`. +/// +/// The intention of this method is to implement the `MapFieldOntoOutput` methods in filters (many +/// of which require this permutation of a field), but can be used in other places as well. +/// +/// `outputField` is set to have the same metadata as the input. If the metadata needs to change +/// (such as the name or the association) that should be done after the function returns. +/// +/// This function returns whether the field was successfully permuted. If the returned result is +/// `true`, then the results in `outputField` are valid. If it is `false`, then `outputField` +/// should not be used. +/// +VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldPermutation( + const vtkm::cont::Field& inputField, + const vtkm::cont::ArrayHandle& permutation, + vtkm::cont::Field& outputField); + +/// \brief Maps a field by permuting it by a given index array. +/// +/// This method will create a new field containing the data from the provided `inputField` but +/// reorded by the given `permutation` index array. The value in the resulting field for index _i_ +/// will be be a value from `inputField`, but comes from the index that comes from `permutation` at +/// position _i_. +/// +/// The intention of this method is to implement the `MapFieldOntoOutput` methods in filters (many +/// of which require this permutation of a field), but can be used in other places as well. The +/// resulting field is put in the given `DataSet`. +/// +/// The returned `Field` has the same metadata as the input. If the metadata needs to change (such +/// as the name or the association), then a different form of `MapFieldPermutation` should be used. +/// +/// This function returns whether the field was successfully permuted. If the returned result is +/// `true`, then `outputData` has the permuted field. If it is `false`, then the field is not +/// placed in `outputData`. +/// +VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldPermutation( + const vtkm::cont::Field& inputField, + const vtkm::cont::ArrayHandle& permutation, + vtkm::cont::DataSet& outputData); +} +} // namespace vtkm::filter + +#endif //vtk_m_filter_MapFieldPermutation_h diff --git a/vtkm/filter/testing/CMakeLists.txt b/vtkm/filter/testing/CMakeLists.txt index 607dc7ed7..f34cf59bc 100644 --- a/vtkm/filter/testing/CMakeLists.txt +++ b/vtkm/filter/testing/CMakeLists.txt @@ -39,6 +39,7 @@ set(unit_tests UnitTestImageMedianFilter.cxx UnitTestLagrangianFilter.cxx UnitTestLagrangianStructuresFilter.cxx + UnitTestMapFieldPermutation.cxx UnitTestMaskFilter.cxx UnitTestMaskPointsFilter.cxx UnitTestMeshQualityFilter.cxx diff --git a/vtkm/filter/testing/UnitTestMapFieldPermutation.cxx b/vtkm/filter/testing/UnitTestMapFieldPermutation.cxx new file mode 100644 index 000000000..c71e78de0 --- /dev/null +++ b/vtkm/filter/testing/UnitTestMapFieldPermutation.cxx @@ -0,0 +1,114 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + +constexpr vtkm::Id ARRAY_SIZE = 26; +constexpr vtkm::Id3 ARRAY3_DIM = { 3, 3, 3 }; + +template +void TryArray(const vtkm::cont::ArrayHandle& inputArray) +{ + std::cout << "Input" << std::endl; + vtkm::cont::printSummary_ArrayHandle(inputArray, std::cout); + + vtkm::cont::Field::Association association = + ((sizeof(T) < 8) ? vtkm::cont::Field::Association::POINTS + : vtkm::cont::Field::Association::CELL_SET); + + vtkm::cont::Field inputField("my-array", association, inputArray); + + vtkm::cont::ArrayHandle permutationArray; + vtkm::cont::ArrayCopy( + vtkm::cont::make_ArrayHandleCounting(0, 2, inputArray.GetNumberOfValues() / 2), + permutationArray); + + vtkm::cont::ArrayHandle expectedOutputArray; + vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandlePermutation(permutationArray, inputArray), + expectedOutputArray); + std::cout << "Expected output" << std::endl; + vtkm::cont::printSummary_ArrayHandle(expectedOutputArray, std::cout); + + vtkm::cont::Field outputField; + bool result = vtkm::filter::MapFieldPermutation(inputField, permutationArray, outputField); + VTKM_TEST_ASSERT(result, "Could not permute the array."); + + VTKM_TEST_ASSERT(outputField.GetAssociation() == association); + VTKM_TEST_ASSERT(outputField.GetName() == "my-array"); + + vtkm::cont::ArrayHandle outputArray; + outputField.GetData().CopyTo(outputArray); + std::cout << "Actual output" << std::endl; + vtkm::cont::printSummary_ArrayHandle(outputArray, std::cout); + + VTKM_TEST_ASSERT(test_equal_portals(expectedOutputArray.ReadPortal(), outputArray.ReadPortal())); +} + +template +void TryType(T) +{ + vtkm::cont::ArrayHandle inputArray; + inputArray.Allocate(ARRAY_SIZE); + SetPortal(inputArray.WritePortal()); + TryArray(inputArray); +} + +struct TryTypeFunctor +{ + template + void operator()(T x) const + { + TryType(x); + } +}; + +void TryCartesianProduct() +{ + vtkm::cont::ArrayHandle axes[3]; + for (vtkm::IdComponent i = 0; i < 3; ++i) + { + axes[i].Allocate(ARRAY3_DIM[i]); + SetPortal(axes[i].WritePortal()); + } + + TryArray(vtkm::cont::make_ArrayHandleCartesianProduct(axes[0], axes[1], axes[2])); +} + +void DoTest() +{ + std::cout << "**** Test Basic Arrays *****" << std::endl; + vtkm::testing::Testing::TryTypes(TryTypeFunctor{}); + + std::cout << std::endl << "**** Test Uniform Point Coordiantes *****" << std::endl; + TryArray(vtkm::cont::ArrayHandleUniformPointCoordinates(ARRAY3_DIM)); + + std::cout << std::endl << "**** Test Cartesian Product *****" << std::endl; + TryCartesianProduct(); +} + +} // anonymous namespace + +int UnitTestMapFieldPermutation(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +}