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); +}