diff --git a/vtkm/filter/CMakeLists.txt b/vtkm/filter/CMakeLists.txt index bb424f638..e0bd2e6dd 100644 --- a/vtkm/filter/CMakeLists.txt +++ b/vtkm/filter/CMakeLists.txt @@ -24,6 +24,8 @@ set(headers ClipWithField.h ClipWithImplicitFunction.h ContourTreeUniform.h + CrossProduct.h + DotProduct.h Entropy.h ExternalFaces.h ExtractGeometry.h @@ -64,6 +66,8 @@ set(header_template_sources ClipWithField.hxx ClipWithImplicitFunction.hxx ContourTreeUniform.hxx + CrossProduct.hxx + DotProduct.hxx Entropy.hxx ExternalFaces.hxx ExtractGeometry.hxx diff --git a/vtkm/filter/CrossProduct.h b/vtkm/filter/CrossProduct.h new file mode 100644 index 000000000..48f13f5c1 --- /dev/null +++ b/vtkm/filter/CrossProduct.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. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#ifndef vtk_m_filter_CrossProduct_h +#define vtk_m_filter_CrossProduct_h + +#include +#include + +namespace vtkm +{ +namespace filter +{ + +class CrossProduct : public vtkm::filter::FilterField +{ +public: + VTKM_CONT + CrossProduct(); + + VTKM_CONT + void SetSecondaryFieldName(const std::string& nm) { SecondaryFieldName = nm; } + + template + VTKM_CONT vtkm::filter::Result DoExecute( + const vtkm::cont::DataSet& input, + const vtkm::cont::ArrayHandle, StorageType>& field, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase& policy, + const DeviceAdapter& tag); + + template + VTKM_CONT bool DoMapField(vtkm::filter::Result& result, + const vtkm::cont::ArrayHandle& input, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase& policy, + DeviceAdapter tag); + +private: + vtkm::worklet::CrossProduct Worklet; + std::string SecondaryFieldName; +}; + +template <> +class FilterTraits +{ //currently the CrossProduct filter only works on vector data. +public: + typedef TypeListTagVecCommon InputFieldTypeList; +}; +} +} // namespace vtkm::filter + +#include + +#endif // vtk_m_filter_CrossProduct_h diff --git a/vtkm/filter/CrossProduct.hxx b/vtkm/filter/CrossProduct.hxx new file mode 100644 index 000000000..3e1faef4e --- /dev/null +++ b/vtkm/filter/CrossProduct.hxx @@ -0,0 +1,84 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include + +namespace vtkm +{ +namespace filter +{ + +//----------------------------------------------------------------------------- +inline VTKM_CONT CrossProduct::CrossProduct() + : vtkm::filter::FilterField() + , Worklet() + , SecondaryFieldName("") +{ + this->SetOutputFieldName("crossproduct"); +} + +//----------------------------------------------------------------------------- +template +inline VTKM_CONT vtkm::filter::Result CrossProduct::DoExecute( + const vtkm::cont::DataSet& inDataSet, + const vtkm::cont::ArrayHandle, StorageType>& field, + const vtkm::filter::FieldMetadata& fieldMetadata, + const vtkm::filter::PolicyBase& policy, + const DeviceAdapter&) +{ + vtkm::cont::ArrayHandle, StorageType> outArray; + + vtkm::worklet::DispatcherMapField dispatcher( + this->Worklet); + + vtkm::cont::ArrayHandle, StorageType> secondaryField; + try + { + vtkm::filter::ApplyPolicy(inDataSet.GetField(SecondaryFieldName), policy) + .CopyTo(secondaryField); + } + catch (const vtkm::cont::Error&) + { + return vtkm::filter::Result(); + } + + dispatcher.Invoke(field, secondaryField, outArray); + + return vtkm::filter::Result(inDataSet, + outArray, + this->GetOutputFieldName(), + fieldMetadata.GetAssociation(), + fieldMetadata.GetCellSetName()); +} + +//----------------------------------------------------------------------------- +template +inline VTKM_CONT bool CrossProduct::DoMapField(vtkm::filter::Result& result, + const vtkm::cont::ArrayHandle& input, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase&, + DeviceAdapter) +{ + //we copy the input handle to the result dataset, reusing the metadata + result.GetDataSet().AddField(fieldMeta.AsField(input)); + return true; +} +} +} // namespace vtkm::filter diff --git a/vtkm/filter/DotProduct.h b/vtkm/filter/DotProduct.h new file mode 100644 index 000000000..ee365ec39 --- /dev/null +++ b/vtkm/filter/DotProduct.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. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#ifndef vtk_m_filter_DotProduct_h +#define vtk_m_filter_DotProduct_h + +#include +#include + +namespace vtkm +{ +namespace filter +{ + +class DotProduct : public vtkm::filter::FilterField +{ +public: + VTKM_CONT + DotProduct(); + + VTKM_CONT + void SetSecondaryFieldName(const std::string& nm) { SecondaryFieldName = nm; } + + template + VTKM_CONT vtkm::filter::Result DoExecute( + const vtkm::cont::DataSet& input, + const vtkm::cont::ArrayHandle, StorageType>& field, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase& policy, + const DeviceAdapter& tag); + + template + VTKM_CONT bool DoMapField(vtkm::filter::Result& result, + const vtkm::cont::ArrayHandle& input, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase& policy, + DeviceAdapter tag); + +private: + vtkm::worklet::DotProduct Worklet; + std::string SecondaryFieldName; +}; + +template <> +class FilterTraits +{ //currently the DotProduct filter only works on vector data. +public: + typedef TypeListTagVecCommon InputFieldTypeList; +}; +} +} // namespace vtkm::filter + +#include + +#endif // vtk_m_filter_DotProduct_h diff --git a/vtkm/filter/DotProduct.hxx b/vtkm/filter/DotProduct.hxx new file mode 100644 index 000000000..f92741e69 --- /dev/null +++ b/vtkm/filter/DotProduct.hxx @@ -0,0 +1,84 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include + +namespace vtkm +{ +namespace filter +{ + +//----------------------------------------------------------------------------- +inline VTKM_CONT DotProduct::DotProduct() + : vtkm::filter::FilterField() + , Worklet() + , SecondaryFieldName("") +{ + this->SetOutputFieldName("crossproduct"); +} + +//----------------------------------------------------------------------------- +template +inline VTKM_CONT vtkm::filter::Result DotProduct::DoExecute( + const vtkm::cont::DataSet& inDataSet, + const vtkm::cont::ArrayHandle, StorageType>& field, + const vtkm::filter::FieldMetadata& fieldMetadata, + const vtkm::filter::PolicyBase& policy, + const DeviceAdapter&) +{ + vtkm::cont::ArrayHandle outArray; + + vtkm::worklet::DispatcherMapField dispatcher( + this->Worklet); + + vtkm::cont::ArrayHandle, StorageType> secondaryField; + try + { + vtkm::filter::ApplyPolicy(inDataSet.GetField(SecondaryFieldName), policy) + .CopyTo(secondaryField); + } + catch (const vtkm::cont::Error&) + { + return vtkm::filter::Result(); + } + + dispatcher.Invoke(field, secondaryField, outArray); + + return vtkm::filter::Result(inDataSet, + outArray, + this->GetOutputFieldName(), + fieldMetadata.GetAssociation(), + fieldMetadata.GetCellSetName()); +} + +//----------------------------------------------------------------------------- +template +inline VTKM_CONT bool DotProduct::DoMapField(vtkm::filter::Result& result, + const vtkm::cont::ArrayHandle& input, + const vtkm::filter::FieldMetadata& fieldMeta, + const vtkm::filter::PolicyBase&, + DeviceAdapter) +{ + //we copy the input handle to the result dataset, reusing the metadata + result.GetDataSet().AddField(fieldMeta.AsField(input)); + return true; +} +} +} // namespace vtkm::filter diff --git a/vtkm/filter/testing/CMakeLists.txt b/vtkm/filter/testing/CMakeLists.txt index 7756a4897..cc08e4531 100644 --- a/vtkm/filter/testing/CMakeLists.txt +++ b/vtkm/filter/testing/CMakeLists.txt @@ -24,6 +24,8 @@ set(unit_tests UnitTestClipWithFieldFilter.cxx UnitTestClipWithImplicitFunctionFilter.cxx UnitTestContourTreeUniformFilter.cxx + UnitTestCrossProductFilter.cxx + UnitTestDotProductFilter.cxx UnitTestEntropyFilter.cxx UnitTestExternalFacesFilter.cxx UnitTestExtractGeometryFilter.cxx diff --git a/vtkm/filter/testing/UnitTestCrossProductFilter.cxx b/vtkm/filter/testing/UnitTestCrossProductFilter.cxx new file mode 100644 index 000000000..dd6d0c422 --- /dev/null +++ b/vtkm/filter/testing/UnitTestCrossProductFilter.cxx @@ -0,0 +1,156 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include +#include +#include + +#include +#include + +namespace +{ +std::mt19937 randGenerator; + +template +void createVectors(std::size_t numPts, + int vecType, + std::vector>& vecs1, + std::vector>& vecs2) +{ + if (vecType == 0) // X x Y + { + vecs1.resize(numPts, vtkm::make_Vec(1, 0, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 1, 0)); + } + else if (vecType == 1) // Y x Z + { + vecs1.resize(numPts, vtkm::make_Vec(0, 1, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 0, 1)); + } + else if (vecType == 2) // Z x X + { + vecs1.resize(numPts, vtkm::make_Vec(0, 0, 1)); + vecs2.resize(numPts, vtkm::make_Vec(1, 0, 0)); + } + else if (vecType == 3) // Y x X + { + vecs1.resize(numPts, vtkm::make_Vec(0, 1, 0)); + vecs2.resize(numPts, vtkm::make_Vec(1, 0, 0)); + } + else if (vecType == 4) // Z x Y + { + vecs1.resize(numPts, vtkm::make_Vec(0, 0, 1)); + vecs2.resize(numPts, vtkm::make_Vec(0, 1, 0)); + } + else if (vecType == 5) // X x Z + { + vecs1.resize(numPts, vtkm::make_Vec(1, 0, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 0, 1)); + } + else if (vecType == 6) + { + //Test some other vector combinations + std::uniform_real_distribution randomDist(-10.0, 10.0); + randomDist(randGenerator); + + vecs1.resize(numPts); + vecs2.resize(numPts); + for (std::size_t i = 0; i < numPts; i++) + { + vecs1[i] = vtkm::make_Vec( + randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)); + vecs2[i] = vtkm::make_Vec( + randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)); + } + } +} + +void TestCrossProduct() +{ + std::cout << "Testing CrossProduct Filter" << std::endl; + + vtkm::cont::testing::MakeTestDataSet testDataSet; + + const int numCases = 7; + for (int i = 0; i < numCases; i++) + { + vtkm::cont::DataSet dataSet = testDataSet.Make3DUniformDataSet0(); + vtkm::Id nVerts = dataSet.GetCoordinateSystem(0).GetData().GetNumberOfValues(); + + std::vector> vecs1, vecs2; + createVectors(static_cast(nVerts), i, vecs1, vecs2); + + vtkm::cont::ArrayHandle> field1, field2; + field1 = vtkm::cont::make_ArrayHandle(vecs1); + field2 = vtkm::cont::make_ArrayHandle(vecs2); + + vtkm::cont::DataSetFieldAdd::AddPointField(dataSet, "vec1", field1); + vtkm::cont::DataSetFieldAdd::AddPointField(dataSet, "vec2", field2); + + vtkm::filter::Result result; + vtkm::filter::CrossProduct filter; + + filter.SetSecondaryFieldName("vec2"); + result = filter.Execute(dataSet, dataSet.GetField("vec1")); + + VTKM_TEST_ASSERT(result.IsValid(), "Result should be valid"); + VTKM_TEST_ASSERT(result.GetField().GetName() == "crossproduct", "Output field has wrong name."); + VTKM_TEST_ASSERT(result.GetField().GetAssociation() == vtkm::cont::Field::ASSOC_POINTS, + "Output field has wrong association"); + + vtkm::cont::ArrayHandle> outputArray; + if (result.FieldAs(outputArray)) + { + auto v1Portal = field1.GetPortalConstControl(); + auto v2Portal = field2.GetPortalConstControl(); + auto outPortal = outputArray.GetPortalConstControl(); + + for (vtkm::Id j = 0; j < outputArray.GetNumberOfValues(); j++) + { + vtkm::Vec v1 = v1Portal.Get(j); + vtkm::Vec v2 = v2Portal.Get(j); + vtkm::Vec res = outPortal.Get(j); + + //Make sure result is orthogonal each input vector. Need to normalize to compare with zero. + vtkm::Vec v1N(vtkm::Normal(v1)), v2N(vtkm::Normal(v1)), + resN(vtkm::Normal(res)); + VTKM_TEST_ASSERT(test_equal(vtkm::dot(resN, v1N), vtkm::FloatDefault(0.0)), + "Wrong result for cross product"); + VTKM_TEST_ASSERT(test_equal(vtkm::dot(resN, v2N), vtkm::FloatDefault(0.0)), + "Wrong result for cross product"); + + vtkm::FloatDefault sinAngle = + vtkm::Magnitude(res) * vtkm::RMagnitude(v1) * vtkm::RMagnitude(v2); + vtkm::FloatDefault cosAngle = + vtkm::dot(v1, v2) * vtkm::RMagnitude(v1) * vtkm::RMagnitude(v2); + VTKM_TEST_ASSERT( + test_equal(sinAngle * sinAngle + cosAngle * cosAngle, vtkm::FloatDefault(1.0)), + "Bad cross product length."); + } + } + } +} +} + +int UnitTestCrossProductFilter(int, char* []) +{ + return vtkm::cont::testing::Testing::Run(TestCrossProduct); +} diff --git a/vtkm/filter/testing/UnitTestDotProductFilter.cxx b/vtkm/filter/testing/UnitTestDotProductFilter.cxx new file mode 100644 index 000000000..e0ef6575c --- /dev/null +++ b/vtkm/filter/testing/UnitTestDotProductFilter.cxx @@ -0,0 +1,142 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include +#include +#include + +#include +#include + +namespace +{ +std::mt19937 randGenerator; + +template +void createVectors(std::size_t numPts, + int vecType, + std::vector>& vecs1, + std::vector>& vecs2) +{ + if (vecType == 0) // X x Y + { + vecs1.resize(numPts, vtkm::make_Vec(1, 0, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 1, 0)); + } + else if (vecType == 1) // Y x Z + { + vecs1.resize(numPts, vtkm::make_Vec(0, 1, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 0, 1)); + } + else if (vecType == 2) // Z x X + { + vecs1.resize(numPts, vtkm::make_Vec(0, 0, 1)); + vecs2.resize(numPts, vtkm::make_Vec(1, 0, 0)); + } + else if (vecType == 3) // Y x X + { + vecs1.resize(numPts, vtkm::make_Vec(0, 1, 0)); + vecs2.resize(numPts, vtkm::make_Vec(1, 0, 0)); + } + else if (vecType == 4) // Z x Y + { + vecs1.resize(numPts, vtkm::make_Vec(0, 0, 1)); + vecs2.resize(numPts, vtkm::make_Vec(0, 1, 0)); + } + else if (vecType == 5) // X x Z + { + vecs1.resize(numPts, vtkm::make_Vec(1, 0, 0)); + vecs2.resize(numPts, vtkm::make_Vec(0, 0, 1)); + } + else if (vecType == 6) + { + //Test some other vector combinations + std::uniform_real_distribution randomDist(-10.0, 10.0); + randomDist(randGenerator); + + vecs1.resize(numPts); + vecs2.resize(numPts); + for (std::size_t i = 0; i < numPts; i++) + { + vecs1[i] = vtkm::make_Vec( + randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)); + vecs2[i] = vtkm::make_Vec( + randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)); + } + } +} + +void TestDotProduct() +{ + std::cout << "Testing DotProduct Filter" << std::endl; + + vtkm::cont::testing::MakeTestDataSet testDataSet; + + const int numCases = 7; + for (int i = 0; i < numCases; i++) + { + vtkm::cont::DataSet dataSet = testDataSet.Make3DUniformDataSet0(); + vtkm::Id nVerts = dataSet.GetCoordinateSystem(0).GetData().GetNumberOfValues(); + + std::vector> vecs1, vecs2; + createVectors(static_cast(nVerts), i, vecs1, vecs2); + + vtkm::cont::ArrayHandle> field1, field2; + field1 = vtkm::cont::make_ArrayHandle(vecs1); + field2 = vtkm::cont::make_ArrayHandle(vecs2); + + vtkm::cont::DataSetFieldAdd::AddPointField(dataSet, "vec1", field1); + vtkm::cont::DataSetFieldAdd::AddPointField(dataSet, "vec2", field2); + + vtkm::filter::Result result; + vtkm::filter::DotProduct filter; + + filter.SetSecondaryFieldName("vec2"); + result = filter.Execute(dataSet, dataSet.GetField("vec1")); + + VTKM_TEST_ASSERT(result.IsValid(), "result should be valid"); + VTKM_TEST_ASSERT(result.GetField().GetName() == "crossproduct", "Output field has wrong name."); + VTKM_TEST_ASSERT(result.GetField().GetAssociation() == vtkm::cont::Field::ASSOC_POINTS, + "Output field has wrong association"); + + vtkm::cont::ArrayHandle outputArray; + if (result.FieldAs(outputArray)) + { + auto v1Portal = field1.GetPortalConstControl(); + auto v2Portal = field2.GetPortalConstControl(); + auto outPortal = outputArray.GetPortalConstControl(); + + for (vtkm::Id j = 0; j < outputArray.GetNumberOfValues(); j++) + { + vtkm::Vec v1 = v1Portal.Get(j); + vtkm::Vec v2 = v2Portal.Get(j); + vtkm::FloatDefault res = outPortal.Get(j); + + VTKM_TEST_ASSERT(test_equal(vtkm::dot(v1, v2), res), "Wrong result for dot product"); + } + } + } +} +} + +int UnitTestDotProductFilter(int, char* []) +{ + return vtkm::cont::testing::Testing::Run(TestDotProduct); +}