From 42c6959be3b122152ffac2058228bbbd4fdf89e0 Mon Sep 17 00:00:00 2001 From: Sujin Philip Date: Wed, 1 Feb 2023 10:58:01 -0500 Subject: [PATCH 01/64] Add Abort execution feature Initial changes to add support for aborting execution. --- docs/changelog/vtkm-abort.md | 22 ++++ vtkm/cont/CMakeLists.txt | 1 + vtkm/cont/ErrorUserAbort.h | 42 ++++++++ vtkm/cont/RuntimeDeviceTracker.cxx | 50 ++++++---- vtkm/cont/RuntimeDeviceTracker.h | 150 ++++++++++++++-------------- vtkm/cont/TryExecute.cxx | 8 ++ vtkm/cont/TryExecute.h | 6 ++ vtkm/cont/testing/CMakeLists.txt | 6 ++ vtkm/cont/testing/UnitTestAbort.cxx | 105 +++++++++++++++++++ vtkm/cont/vtkm.module | 1 + 10 files changed, 296 insertions(+), 95 deletions(-) create mode 100644 docs/changelog/vtkm-abort.md create mode 100644 vtkm/cont/ErrorUserAbort.h create mode 100644 vtkm/cont/testing/UnitTestAbort.cxx diff --git a/docs/changelog/vtkm-abort.md b/docs/changelog/vtkm-abort.md new file mode 100644 index 000000000..8bd25c7d0 --- /dev/null +++ b/docs/changelog/vtkm-abort.md @@ -0,0 +1,22 @@ +# Add initial support for aborting execution + +VTK-m now has preliminary support for aborting execution. The per-thread instances of +`RuntimeDeviceTracker` have a functor called `AbortChecker`. This functor can be set using +`RuntimeDeviceTracker::SetAbortChecker()` and cleared by `RuntimeDeviceTracker::ClearAbortChecker()` +The abort checker functor should return `true` if an abort is requested for the thread, +otherwise, it should return `false`. + +Before launching a new task, `TaskExecute` calls the functor to see if an abort is requested, +and If so, throws an exception of type `vtkm::cont::ErrorUserAbort`. + +Any code that wants to use the abort feature, should set an appropriate `AbortChecker` +functor for the target thread. Then any piece of code that has parts that can execute on +the device should be put under a `try-catch` block. Any clean-up that is required for an +aborted execution should be handled in a `catch` block that handles exceptions of type +`vtkm::cont::ErrorUserAbort`. + +The limitation of this implementation is that it is control-side only. The check for abort +is done before launching a new device task. Once execution has begun on the device, there is +currently no way to abort that. Therefore, this feature is only useful for aborting code +that is made up of several smaller device task launches (Which is the case for most +worklets and filters in VTK-m) diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 35f356527..761652c22 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -94,6 +94,7 @@ set(headers ErrorExecution.h ErrorFilterExecution.h ErrorInternal.h + ErrorUserAbort.h ExecutionAndControlObjectBase.h ExecutionObjectBase.h Field.h diff --git a/vtkm/cont/ErrorUserAbort.h b/vtkm/cont/ErrorUserAbort.h new file mode 100644 index 000000000..04f6371b9 --- /dev/null +++ b/vtkm/cont/ErrorUserAbort.h @@ -0,0 +1,42 @@ +//============================================================================ +// 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_ErrorUserAbort_h +#define vtk_m_cont_ErrorUserAbort_h + +#include + +namespace vtkm +{ +namespace cont +{ + +VTKM_SILENCE_WEAK_VTABLE_WARNING_START + +/// This class is thrown when vtk-m detects a request for aborting execution +/// in the current thread +/// +class VTKM_ALWAYS_EXPORT ErrorUserAbort : public Error +{ +public: + ErrorUserAbort() + : Error(Message, true) + { + } + +private: + static constexpr const char* Message = "User abort detected."; +}; + +VTKM_SILENCE_WEAK_VTABLE_WARNING_END + +} +} // namespace vtkm::cont + +#endif // vtk_m_cont_ErrorUserAbort_h diff --git a/vtkm/cont/RuntimeDeviceTracker.cxx b/vtkm/cont/RuntimeDeviceTracker.cxx index ce6fcdf17..89d2e9eab 100644 --- a/vtkm/cont/RuntimeDeviceTracker.cxx +++ b/vtkm/cont/RuntimeDeviceTracker.cxx @@ -35,6 +35,7 @@ struct RuntimeDeviceTrackerInternals std::array RuntimeAllowed; bool ThreadFriendlyMemAlloc = false; + std::function AbortChecker; }; } @@ -186,6 +187,28 @@ VTKM_CONT void RuntimeDeviceTracker::CopyStateFrom(const vtkm::cont::RuntimeDevi *(this->Internals) = *tracker.Internals; } +VTKM_CONT +void RuntimeDeviceTracker::SetAbortChecker(const std::function& func) +{ + this->Internals->AbortChecker = func; +} + +VTKM_CONT +bool RuntimeDeviceTracker::CheckForAbortRequest() const +{ + if (this->Internals->AbortChecker) + { + return this->Internals->AbortChecker(); + } + return false; +} + +VTKM_CONT +void RuntimeDeviceTracker::ClearAbortChecker() +{ + this->Internals->AbortChecker = nullptr; +} + VTKM_CONT void RuntimeDeviceTracker::PrintSummary(std::ostream& out) const { @@ -228,25 +251,6 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker( VTKM_LOG_S(vtkm::cont::LogLevel::DevicesEnabled, "Entering scoped runtime region"); } -VTKM_CONT -ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device, - RuntimeDeviceTrackerMode mode) - : ScopedRuntimeDeviceTracker(GetRuntimeDeviceTracker()) -{ - if (mode == RuntimeDeviceTrackerMode::Force) - { - this->ForceDevice(device); - } - else if (mode == RuntimeDeviceTrackerMode::Enable) - { - this->ResetDevice(device); - } - else if (mode == RuntimeDeviceTrackerMode::Disable) - { - this->DisableDevice(device); - } -} - VTKM_CONT ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker( vtkm::cont::DeviceAdapterId device, @@ -268,6 +272,14 @@ ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker( } } +VTKM_CONT ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker( + const std::function& abortChecker, + const vtkm::cont::RuntimeDeviceTracker& tracker) + : ScopedRuntimeDeviceTracker(tracker) +{ + this->SetAbortChecker(abortChecker); +} + VTKM_CONT ScopedRuntimeDeviceTracker::~ScopedRuntimeDeviceTracker() { diff --git a/vtkm/cont/RuntimeDeviceTracker.h b/vtkm/cont/RuntimeDeviceTracker.h index 5de7c22bc..c847ec92a 100644 --- a/vtkm/cont/RuntimeDeviceTracker.h +++ b/vtkm/cont/RuntimeDeviceTracker.h @@ -17,6 +17,7 @@ #include #include +#include #include namespace vtkm @@ -123,6 +124,18 @@ public: /// VTKM_CONT void CopyStateFrom(const vtkm::cont::RuntimeDeviceTracker& tracker); + ///@{ + /// \brief Set/Clear the abort checker functor. + /// + /// If set the abort checker functor is called by \c TryExecute before scheduling + /// a task on a device from the associated the thread. If the functor returns + /// \e true, an exception is thrown. + VTKM_CONT void SetAbortChecker(const std::function& func); + VTKM_CONT void ClearAbortChecker(); + ///@} + + VTKM_CONT bool CheckForAbortRequest() const; + VTKM_CONT void PrintSummary(std::ostream& out) const; private: @@ -149,82 +162,7 @@ private: void LogEnabledDevices() const; }; - -enum struct RuntimeDeviceTrackerMode -{ - Force, - Enable, - Disable -}; - -/// A class that can be used to determine or modify which device adapter -/// VTK-m algorithms should be run on. This class captures the state -/// of the per-thread device adapter and will revert any changes applied -/// during its lifetime on destruction. -/// -/// -struct VTKM_CONT_EXPORT ScopedRuntimeDeviceTracker : public vtkm::cont::RuntimeDeviceTracker -{ - /// Construct a ScopedRuntimeDeviceTracker where the state of the active devices - /// for the current thread are determined by the parameters to the constructor. - /// - /// 'Force' - /// - Force-Enable the provided single device adapter - /// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny - /// 'Enable' - /// - Enable the provided single device adapter if it was previously disabled - /// - Enable all device adapters that are currently disabled when using - /// vtkm::cont::DeviceAdaterTagAny - /// 'Disable' - /// - Disable the provided single device adapter - /// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny - /// - /// Constructor is not thread safe - VTKM_CONT ScopedRuntimeDeviceTracker( - vtkm::cont::DeviceAdapterId device, - RuntimeDeviceTrackerMode mode = RuntimeDeviceTrackerMode::Force); - - /// Construct a ScopedRuntimeDeviceTracker associated with the thread - /// associated with the provided tracker. The active devices - /// for the current thread are determined by the parameters to the constructor. - /// - /// 'Force' - /// - Force-Enable the provided single device adapter - /// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny - /// 'Enable' - /// - Enable the provided single device adapter if it was previously disabled - /// - Enable all device adapters that are currently disabled when using - /// vtkm::cont::DeviceAdaterTagAny - /// 'Disable' - /// - Disable the provided single device adapter - /// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny - /// - /// Any modifications to the ScopedRuntimeDeviceTracker will effect what - /// ever thread the \c tracker is associated with, which might not be - /// the thread which ScopedRuntimeDeviceTracker was constructed on. - /// - /// Constructor is not thread safe - VTKM_CONT ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device, - RuntimeDeviceTrackerMode mode, - const vtkm::cont::RuntimeDeviceTracker& tracker); - - /// Construct a ScopedRuntimeDeviceTracker associated with the thread - /// associated with the provided tracker. - /// - /// Any modifications to the ScopedRuntimeDeviceTracker will effect what - /// ever thread the \c tracker is associated with, which might not be - /// the thread which ScopedRuntimeDeviceTracker was constructed on. - /// - /// Constructor is not thread safe - VTKM_CONT ScopedRuntimeDeviceTracker(const vtkm::cont::RuntimeDeviceTracker& tracker); - - /// Destructor is not thread safe - VTKM_CONT ~ScopedRuntimeDeviceTracker(); - -private: - std::unique_ptr SavedState; -}; - +///---------------------------------------------------------------------------- /// \brief Get the \c RuntimeDeviceTracker for the current thread. /// /// Many features in VTK-m will attempt to run algorithms on the "best @@ -236,6 +174,66 @@ private: VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::RuntimeDeviceTracker& GetRuntimeDeviceTracker(); + +enum struct RuntimeDeviceTrackerMode +{ + Force, + Enable, + Disable +}; + +///---------------------------------------------------------------------------- +/// A class to create a scoped runtime device tracker object. This object captures the state +/// of the per-thread device tracker and will revert any changes applied +/// during its lifetime on destruction. +/// +struct VTKM_CONT_EXPORT ScopedRuntimeDeviceTracker : public vtkm::cont::RuntimeDeviceTracker +{ + /// Construct a ScopedRuntimeDeviceTracker associated with the thread, + /// associated with the provided tracker (defaults to current thread's tracker). + /// + /// Any modifications to the ScopedRuntimeDeviceTracker will effect what + /// ever thread the \c tracker is associated with, which might not be + /// the thread on which the ScopedRuntimeDeviceTracker was constructed. + /// + /// Constructors are not thread safe + /// @{ + /// + VTKM_CONT ScopedRuntimeDeviceTracker( + const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker()); + + /// Use this constructor to modify the state of the device adapters associated with + /// the provided tracker. Use \p mode with \p device as follows: + /// + /// 'Force' (default) + /// - Force-Enable the provided single device adapter + /// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny + /// 'Enable' + /// - Enable the provided single device adapter if it was previously disabled + /// - Enable all device adapters that are currently disabled when using + /// vtkm::cont::DeviceAdaterTagAny + /// 'Disable' + /// - Disable the provided single device adapter + /// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny + /// + VTKM_CONT ScopedRuntimeDeviceTracker( + vtkm::cont::DeviceAdapterId device, + RuntimeDeviceTrackerMode mode = RuntimeDeviceTrackerMode::Force, + const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker()); + + /// Use this constructor to set the abort checker functor for the provided tracker. + /// + VTKM_CONT ScopedRuntimeDeviceTracker( + const std::function& abortChecker, + const vtkm::cont::RuntimeDeviceTracker& tracker = GetRuntimeDeviceTracker()); + + /// Destructor is not thread safe + VTKM_CONT ~ScopedRuntimeDeviceTracker(); + +private: + std::unique_ptr SavedState; +}; + } } // namespace vtkm::cont diff --git a/vtkm/cont/TryExecute.cxx b/vtkm/cont/TryExecute.cxx index 8b2f9b37f..59503c818 100644 --- a/vtkm/cont/TryExecute.cxx +++ b/vtkm/cont/TryExecute.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace vtkm @@ -55,6 +56,13 @@ VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::cont::DeviceAdapterId devi VTKM_LOG_TRYEXECUTE_FAIL("ErrorBadValue (" << e.GetMessage() << ")", functorName, deviceId); throw; } + catch (vtkm::cont::ErrorUserAbort& e) + { + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + e.GetMessage() << " Aborting: " << functorName << ", on device " + << deviceId.GetName()); + throw; + } catch (vtkm::cont::Error& e) { VTKM_LOG_TRYEXECUTE_FAIL(e.GetMessage(), functorName, deviceId); diff --git a/vtkm/cont/TryExecute.h b/vtkm/cont/TryExecute.h index 78942afa2..f62138149 100644 --- a/vtkm/cont/TryExecute.h +++ b/vtkm/cont/TryExecute.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -40,6 +41,11 @@ inline bool TryExecuteIfValid(std::true_type, { try { + if (tracker.CheckForAbortRequest()) + { + throw vtkm::cont::ErrorUserAbort{}; + } + return f(tag, std::forward(args)...); } catch (...) diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index e5711e5ea..ef4c4e566 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -122,6 +122,12 @@ if(TARGET vtkm_filter_field_conversion) ) endif() +if(TARGET vtkm_filter_contour) + list(APPEND unit_tests_device + UnitTestAbort.cxx + ) +endif() + vtkm_unit_tests(SOURCES ${unit_tests} DEVICE_SOURCES ${unit_tests_device}) #add distributed tests i.e.test to run with MPI diff --git a/vtkm/cont/testing/UnitTestAbort.cxx b/vtkm/cont/testing/UnitTestAbort.cxx new file mode 100644 index 000000000..a9cd50335 --- /dev/null +++ b/vtkm/cont/testing/UnitTestAbort.cxx @@ -0,0 +1,105 @@ +//============================================================================ +// 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 +{ + +// A function that checks for abort request. +// This function will be called by `TryExecute` befaure lauching a device task +// to check if abort has been requested. +// For this test case, we are using a simple logic of returning true for the +// `abortAt`th check. +// If this test is failing, one of the things to check would be to see if the +// `Contour` filter has changed such that it no longer has atleast `abortAt` +// task invocations. +bool ShouldAbort() +{ + static int abortCheckCounter = 0; + static constexpr int abortAt = 5; + if (++abortCheckCounter >= abortAt) + { + std::cout << "Abort check " << abortCheckCounter << ": true\n"; + return true; + } + + std::cout << "Abort check " << abortCheckCounter << ": false\n"; + return false; +} + +int TestAbort() +{ + vtkm::source::Wavelet wavelet; + wavelet.SetExtent(vtkm::Id3(-15), vtkm::Id3(16)); + auto input = wavelet.Execute(); + + auto range = input.GetField("RTData").GetRange().ReadPortal().Get(0); + std::vector isovals; + static constexpr int numDivs = 5; + for (int i = 1; i < numDivs - 1; ++i) + { + auto v = range.Min + + (static_cast(i) * + ((range.Max - range.Min) / static_cast(numDivs))); + isovals.push_back(v); + } + + vtkm::filter::contour::Contour contour; + contour.SetActiveField("RTData"); + contour.SetIsoValues(isovals); + + // First we will run the filter with the abort function set + std::cout << "Run #1 with the abort function set\n"; + try + { + vtkm::cont::ScopedRuntimeDeviceTracker tracker(ShouldAbort); + + auto result = contour.Execute(input); + + // execution shouldn't reach here + VTKM_TEST_FAIL("Error: filter execution was not aborted. Result: ", + result.GetNumberOfPoints(), + " points and ", + result.GetNumberOfCells(), + " triangles"); + } + catch (const vtkm::cont::ErrorUserAbort& e) + { + std::cout << "Execution was successfully aborted\n"; + } + + // Now run the filter without the abort function + std::cout << "Run #2 without the abort function set\n"; + try + { + auto result = contour.Execute(input); + std::cout << "Success: filter execution was not aborted. Result: " << result.GetNumberOfPoints() + << " points and " << result.GetNumberOfCells() << " triangles\n"; + } + catch (const vtkm::cont::ErrorUserAbort& e) + { + VTKM_TEST_FAIL("Execution was unexpectedly aborted"); + } + + return 0; +} +} // anon namespace + +int UnitTestAbort(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(TestAbort, argc, argv); +} diff --git a/vtkm/cont/vtkm.module b/vtkm/cont/vtkm.module index 33396e7ae..587729dce 100644 --- a/vtkm/cont/vtkm.module +++ b/vtkm/cont/vtkm.module @@ -9,6 +9,7 @@ DEPENDS OPTIONAL_DEPENDS vtkm_loguru TEST_OPTIONAL_DEPENDS + vtkm_filter_contour vtkm_filter_field_conversion TEST_DEPENDS vtkm_source From a80de8019aaff33f7a0cd271fd833d3de1678548 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 9 Feb 2023 09:42:38 -0700 Subject: [PATCH 02/64] Add support for getting vec sizes of unknown arrays when runtime selected The `GetNumberOfComponents` and `GetNumberOfComponentsFlat` methods in `UnknownArrayHandle` have been updated to correctly report the number of components in special `ArrayHandle`s where the `Vec` sizes of the values are not selected until runtime. Previously, these methods always reported 0 because the value type could not report the size of the `Vec`. The lookup has been modified to query the `ArrayHandle`'s `Storage` for the number of components where supported. Note that this only works on `Storage` that provides a method to get the runtime `Vec` size. If that is not provided, as will be the case if the number of components can vary from one value to the next, it will still report 0. This feature is implemented by looking for a method named `GetNumberOfComponents` is the `Storage` class for the `ArrayHandle`. If this method is found, it is used to query the size at runtime. --- .../unknownarray-runtime-components.md | 18 +++ vtkm/cont/ArrayHandleRecombineVec.h | 10 +- vtkm/cont/UnknownArrayHandle.cxx | 4 +- vtkm/cont/UnknownArrayHandle.h | 119 ++++++++++++------ 4 files changed, 104 insertions(+), 47 deletions(-) create mode 100644 docs/changelog/unknownarray-runtime-components.md diff --git a/docs/changelog/unknownarray-runtime-components.md b/docs/changelog/unknownarray-runtime-components.md new file mode 100644 index 000000000..86119ee1e --- /dev/null +++ b/docs/changelog/unknownarray-runtime-components.md @@ -0,0 +1,18 @@ +# Added support for getting vec sizes of unknown arrays when runtime selected + +The `GetNumberOfComponents` and `GetNumberOfComponentsFlat` methods in +`UnknownArrayHandle` have been updated to correctly report the number of +components in special `ArrayHandle`s where the `Vec` sizes of the values +are not selected until runtime. + +Previously, these methods always reported 0 because the value type could +not report the size of the `Vec`. The lookup has been modified to query the +`ArrayHandle`'s `Storage` for the number of components where supported. +Note that this only works on `Storage` that provides a method to get the +runtime `Vec` size. If that is not provided, as will be the case if the +number of components can vary from one value to the next, it will still +report 0. + +This feature is implemented by looking for a method named +`GetNumberOfComponents` is the `Storage` class for the `ArrayHandle`. If +this method is found, it is used to query the size at runtime. diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index 14e971ee8..cb5f6bf80 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -437,7 +437,7 @@ public: using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec; using WritePortalType = vtkm::internal::ArrayPortalRecombineVec; - VTKM_CONT static vtkm::IdComponent NumberOfComponents( + VTKM_CONT static vtkm::IdComponent GetNumberOfComponents( const std::vector& buffers) { return static_cast( @@ -455,7 +455,7 @@ public: vtkm::CopyFlag preserve, vtkm::cont::Token& token) { - vtkm::IdComponent numComponents = NumberOfComponents(buffers); + vtkm::IdComponent numComponents = GetNumberOfComponents(buffers); for (vtkm::IdComponent component = 0; component < numComponents; ++component) { SourceStorage::ResizeBuffers( @@ -477,7 +477,7 @@ public: vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { - vtkm::IdComponent numComponents = NumberOfComponents(buffers); + vtkm::IdComponent numComponents = GetNumberOfComponents(buffers); // The array portal needs a runtime-allocated array of portals for each component. // We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the @@ -515,7 +515,7 @@ public: vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { - vtkm::IdComponent numComponents = NumberOfComponents(buffers); + vtkm::IdComponent numComponents = GetNumberOfComponents(buffers); // The array portal needs a runtime-allocated array of portals for each component. // We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the @@ -608,7 +608,7 @@ private: public: vtkm::IdComponent GetNumberOfComponents() const { - return StorageType::NumberOfComponents(this->GetBuffers()); + return StorageType::GetNumberOfComponents(this->GetBuffers()); } vtkm::cont::ArrayHandleStride GetComponentArray( diff --git a/vtkm/cont/UnknownArrayHandle.cxx b/vtkm/cont/UnknownArrayHandle.cxx index 4fcfb555d..dde409c17 100644 --- a/vtkm/cont/UnknownArrayHandle.cxx +++ b/vtkm/cont/UnknownArrayHandle.cxx @@ -265,7 +265,7 @@ vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponents() const { if (this->Container) { - return this->Container->NumberOfComponents(); + return this->Container->NumberOfComponents(this->Container->ArrayHandlePointer); } else { @@ -277,7 +277,7 @@ VTKM_CONT vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponentsFlat() cons { if (this->Container) { - return this->Container->NumberOfComponentsFlat(); + return this->Container->NumberOfComponentsFlat(this->Container->ArrayHandlePointer); } else { diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 3adf055e6..1f8c2b0e6 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -56,49 +56,88 @@ vtkm::Id UnknownAHNumberOfValues(void* mem) return arrayHandle->GetNumberOfValues(); } -template ::IsSizeStatic> -struct UnknownAHNumberOfComponentsImpl; -template -struct UnknownAHNumberOfComponentsImpl +// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise +template +inline auto UnknownAHNumberOfComponentsImpl(void* mem) + -> decltype(vtkm::cont::internal::Storage::GetNumberOfComponents( + std::vector())) { - static constexpr vtkm::IdComponent Value = vtkm::internal::SafeVecTraits::NUM_COMPONENTS; -}; -template -struct UnknownAHNumberOfComponentsImpl -{ - static constexpr vtkm::IdComponent Value = 0; -}; - -template -vtkm::IdComponent UnknownAHNumberOfComponents() -{ - return UnknownAHNumberOfComponentsImpl::Value; + using AH = vtkm::cont::ArrayHandle; + AH* arrayHandle = reinterpret_cast(mem); + return vtkm::cont::internal::Storage::GetNumberOfComponents(arrayHandle->GetBuffers()); } -template ::IsSizeStatic, - typename = vtkm::HasVecTraits> -struct UnknownAHNumberOfComponentsFlatImpl; -template -struct UnknownAHNumberOfComponentsFlatImpl +// Uses SFINAE to use the number of compnents in VecTraits. +// Note that this will conflict with the above overloaded function if the storage has a +// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think +// of a use case for the storage to report the number of components for a static data type. +// If that happens, this implementation will need to be modified. +template +inline auto UnknownAHNumberOfComponentsImpl(void*) + -> decltype(vtkm::internal::SafeVecTraits::NUM_COMPONENTS) { - static constexpr vtkm::IdComponent Value = vtkm::VecFlat::NUM_COMPONENTS; -}; -template -struct UnknownAHNumberOfComponentsFlatImpl -{ - static constexpr vtkm::IdComponent Value = 0; -}; -template -struct UnknownAHNumberOfComponentsFlatImpl -{ - static constexpr vtkm::IdComponent Value = 1; -}; + static constexpr vtkm::IdComponent numComponents = + vtkm::internal::SafeVecTraits::NUM_COMPONENTS; + return numComponents; +} -template -vtkm::IdComponent UnknownAHNumberOfComponentsFlat() +// Fallback for when there is no way to determine the number of components. (This could be +// because each value could have a different number of components. +template +inline vtkm::IdComponent UnknownAHNumberOfComponentsImpl(...) { - return UnknownAHNumberOfComponentsFlatImpl::Value; + return 0; +} + +template +vtkm::IdComponent UnknownAHNumberOfComponents(void* mem) +{ + return UnknownAHNumberOfComponentsImpl(mem); +} + +// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise +template +inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem) + -> decltype(vtkm::cont::internal::Storage::GetNumberOfComponents( + std::vector())) +{ + using AH = vtkm::cont::ArrayHandle; + AH* arrayHandle = reinterpret_cast(mem); + // Making an assumption here that `T` is a `Vec`-like object that `GetNumberOfComponents` + // will report on how many each has. Further assuming that the components of `T` are + // static. If a future `ArrayHandle` type violates this, this code will have to become + // more complex. + return (vtkm::cont::internal::Storage::GetNumberOfComponents(arrayHandle->GetBuffers()) * + vtkm::VecFlat::ComponentType>::NUM_COMPONENTS); +} + +// Uses SFINAE to use the number of compnents in VecTraits. +// Note that this will conflict with the above overloaded function if the storage has a +// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think +// of a use case for the storage to report the number of components for a static data type. +// If that happens, this implementation will need to be modified. +template +inline auto UnknownAHNumberOfComponentsFlatImpl(void*) + -> decltype(vtkm::VecTraits::NUM_COMPONENTS) +{ + // static constexpr vtkm::IdComponent numComponents = vtkm::VecFlat::NUM_COMPONENTS; + // return numComponents; + return vtkm::VecFlat::NUM_COMPONENTS; +} + +// Fallback for when there is no way to determine the number of components. (This could be +// because each value could have a different number of components or just that VecTraits +// are not defined.) Since it cannot be flattened, just return the same as num components. +template +inline vtkm::IdComponent UnknownAHNumberOfComponentsFlatImpl(...) +{ + return UnknownAHNumberOfComponentsImpl(static_cast(nullptr)); +} + +template +vtkm::IdComponent UnknownAHNumberOfComponentsFlat(void* mem) +{ + return UnknownAHNumberOfComponentsFlatImpl(mem); } template @@ -230,7 +269,7 @@ struct VTKM_CONT_EXPORT UnknownAHContainer using NumberOfValuesType = vtkm::Id(void*); NumberOfValuesType* NumberOfValues; - using NumberOfComponentsType = vtkm::IdComponent(); + using NumberOfComponentsType = vtkm::IdComponent(void*); NumberOfComponentsType* NumberOfComponents; NumberOfComponentsType* NumberOfComponentsFlat; @@ -348,8 +387,8 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle) , NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic) , NumberOfValues(detail::UnknownAHNumberOfValues) - , NumberOfComponents(detail::UnknownAHNumberOfComponents) - , NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat) + , NumberOfComponents(detail::UnknownAHNumberOfComponents) + , NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat) , Allocate(detail::UnknownAHAllocate) , ShallowCopy(detail::UnknownAHShallowCopy) , DeepCopy(detail::UnknownAHDeepCopy) From a51cc2e153bdeb2dab8549a2d127cb964d8c4e53 Mon Sep 17 00:00:00 2001 From: Sujin Philip Date: Mon, 13 Feb 2023 13:29:26 -0500 Subject: [PATCH 03/64] Fix unreferenced local variable warning --- vtkm/cont/testing/UnitTestAbort.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vtkm/cont/testing/UnitTestAbort.cxx b/vtkm/cont/testing/UnitTestAbort.cxx index a9cd50335..c56c48d23 100644 --- a/vtkm/cont/testing/UnitTestAbort.cxx +++ b/vtkm/cont/testing/UnitTestAbort.cxx @@ -77,7 +77,7 @@ int TestAbort() result.GetNumberOfCells(), " triangles"); } - catch (const vtkm::cont::ErrorUserAbort& e) + catch (const vtkm::cont::ErrorUserAbort&) { std::cout << "Execution was successfully aborted\n"; } @@ -90,7 +90,7 @@ int TestAbort() std::cout << "Success: filter execution was not aborted. Result: " << result.GetNumberOfPoints() << " points and " << result.GetNumberOfCells() << " triangles\n"; } - catch (const vtkm::cont::ErrorUserAbort& e) + catch (const vtkm::cont::ErrorUserAbort&) { VTKM_TEST_FAIL("Execution was unexpectedly aborted"); } From 5a141349a925a67e4d551eed5b6438ee17b64aa9 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 13 Feb 2023 14:06:43 -0700 Subject: [PATCH 04/64] Fix the passing of fields in filters While updating the user's guide, I noticed a couple of minor problems with how filters map fields. First, if a filter was using `CreateResultCoordinateSystem`, it did not respect the `PassCoordinateSystems` flag. Second, if both an `initializer_list` and a mode was given to `SetFieldsToPass`, the mode was captured incorrectly. Both problems are corrected. --- docs/changelog/fix-filter-pass-fields.md | 26 ++++++++++++++ docs/changelog/fix-pass-coords.md | 9 +++++ vtkm/filter/Filter.cxx | 41 +++++++++++++++++++++- vtkm/filter/Filter.h | 43 ++++++++++++++---------- 4 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 docs/changelog/fix-filter-pass-fields.md create mode 100644 docs/changelog/fix-pass-coords.md diff --git a/docs/changelog/fix-filter-pass-fields.md b/docs/changelog/fix-filter-pass-fields.md new file mode 100644 index 000000000..5854a1fe4 --- /dev/null +++ b/docs/changelog/fix-filter-pass-fields.md @@ -0,0 +1,26 @@ +# Fix setting fields to pass in `Filter` when setting mode + +The `Filter` class has several version of the `SetFieldsToPass` method that +works in conjunction with the `FieldSelection` object to specify which +fields are mapped. For example, the user might have code like this to pass +all fields except those named `pointvar` and `cellvar`: + +``` cpp + filter.SetFieldsToPass({ "pointvar", "cellvar" }, + vtkm::filter::FieldSelection::Mode::Exclude); +``` + +This previously worked by implicitly creating a `FieldSelection` object +using the `std::initializer_list` filled with the 2 strings. This would +then be passed to the `SetFieldsToPass` method, which would capture the +`FieldSelection` object and change the mode. + +This stopped working in a recent change to `FieldSelection` where each +entry is given its own mode. With this new class, the `FieldSelection` +constructor would capture each field in the default mode (`Select`) and +then change the default mode to `Exclude`. However, the already set modes +kept their `Select` status, which is not what is intended. + +This behavior is fixed by adding `SetFieldToPass` overloads that capture +both the `initializer_list` and the `Mode` and then constructs the +`FieldSelection` correctly. diff --git a/docs/changelog/fix-pass-coords.md b/docs/changelog/fix-pass-coords.md new file mode 100644 index 000000000..a95a04da8 --- /dev/null +++ b/docs/changelog/fix-pass-coords.md @@ -0,0 +1,9 @@ +# Respect `Filter::PassCoordinateSystem` flag in filters creating coordinate systems + +The `Filter` class has a `PassCoordinateSystem` flag that specifies whether +coordinate systems should be passed regardless of whether the associated +field is passed. However, if a filter created its output with the +`CreateResultCoordinateSystem` method this flag was ignored, and the +provided coordinate system was always passed. This might not be what the +user intended, so this method has been fixed to first check the +`PassCoordinateSystem` flag before setting the coordinates on the output. diff --git a/vtkm/filter/Filter.cxx b/vtkm/filter/Filter.cxx index c1586f965..924940775 100644 --- a/vtkm/filter/Filter.cxx +++ b/vtkm/filter/Filter.cxx @@ -40,7 +40,7 @@ void RunFilter(Filter* self, vtkm::filter::DataSetQueue& input, vtkm::filter::Da tracker.SetThreadFriendlyMemAlloc(prevVal); } -} +} // anonymous namespace Filter::~Filter() = default; @@ -49,6 +49,45 @@ bool Filter::CanThread() const return true; } +//---------------------------------------------------------------------------- +void Filter::SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass) +{ + this->FieldsToPass = fieldsToPass; +} + +void Filter::SetFieldsToPass(vtkm::filter::FieldSelection&& fieldsToPass) +{ + this->FieldsToPass = std::move(fieldsToPass); +} + +void Filter::SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass, + vtkm::filter::FieldSelection::Mode mode) +{ + this->FieldsToPass = fieldsToPass; + this->FieldsToPass.SetMode(mode); +} + +VTKM_CONT void Filter::SetFieldsToPass(std::initializer_list fields, + vtkm::filter::FieldSelection::Mode mode) +{ + this->SetFieldsToPass(vtkm::filter::FieldSelection{ fields, mode }); +} + +void Filter::SetFieldsToPass( + std::initializer_list> fields, + vtkm::filter::FieldSelection::Mode mode) +{ + this->SetFieldsToPass(vtkm::filter::FieldSelection{ fields, mode }); +} + +void Filter::SetFieldsToPass(const std::string& fieldname, + vtkm::cont::Field::Association association, + vtkm::filter::FieldSelection::Mode mode) +{ + this->SetFieldsToPass(vtkm::filter::FieldSelection{ fieldname, association, mode }); +} + + //---------------------------------------------------------------------------- vtkm::cont::PartitionedDataSet Filter::DoExecutePartitions( const vtkm::cont::PartitionedDataSet& input) diff --git a/vtkm/filter/Filter.h b/vtkm/filter/Filter.h index 3e171362a..471c13500 100644 --- a/vtkm/filter/Filter.h +++ b/vtkm/filter/Filter.h @@ -263,27 +263,31 @@ public: /// /// By default, all fields are passed during execution. /// - VTKM_CONT - void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass) - { - this->FieldsToPass = fieldsToPass; - } + VTKM_CONT void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass); + VTKM_CONT void SetFieldsToPass(vtkm::filter::FieldSelection&& fieldsToPass); - VTKM_CONT - void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass, - vtkm::filter::FieldSelection::Mode mode) - { - this->FieldsToPass = fieldsToPass; - this->FieldsToPass.SetMode(mode); - } + VTKM_DEPRECATED(2.0) + VTKM_CONT void SetFieldsToPass(const vtkm::filter::FieldSelection& fieldsToPass, + vtkm::filter::FieldSelection::Mode mode); - VTKM_CONT - void SetFieldsToPass( + VTKM_CONT void SetFieldsToPass( + std::initializer_list fields, + vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select); + + VTKM_CONT void SetFieldsToPass( + std::initializer_list> fields, + vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select); + + + VTKM_CONT void SetFieldsToPass( const std::string& fieldname, vtkm::cont::Field::Association association, - vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select) + vtkm::filter::FieldSelection::Mode mode = vtkm::filter::FieldSelection::Mode::Select); + + VTKM_CONT void SetFieldsToPass(const std::string& fieldname, + vtkm::filter::FieldSelection::Mode mode) { - this->SetFieldsToPass({ fieldname, association }, mode); + this->SetFieldsToPass(fieldname, vtkm::cont::Field::Association::Any, mode); } VTKM_CONT @@ -442,9 +446,12 @@ protected: { vtkm::cont::DataSet outDataSet; outDataSet.SetCellSet(resultCellSet); - outDataSet.AddCoordinateSystem(resultCoordSystem); vtkm::filter::FieldSelection fieldSelection = this->GetFieldsToPass(); - fieldSelection.AddField(resultCoordSystem, vtkm::filter::FieldSelection::Mode::Exclude); + if (this->GetPassCoordinateSystems() || fieldSelection.HasField(resultCoordSystem)) + { + outDataSet.AddCoordinateSystem(resultCoordSystem); + fieldSelection.AddField(resultCoordSystem, vtkm::filter::FieldSelection::Mode::Exclude); + } this->MapFieldsOntoOutput(inDataSet, fieldSelection, outDataSet, fieldMapper); return outDataSet; } From 7d3ea2126d57769f0be3815134a2775b19f2428c Mon Sep 17 00:00:00 2001 From: Mark Bolstad Date: Wed, 1 Feb 2023 16:12:49 -0700 Subject: [PATCH 05/64] Changes for compiling with SYCL - Remove volatile keyword from `join' - Remove various `printf' in device code --- .../internal/DeviceAdapterAlgorithmKokkos.h | 5 +---- vtkm/cont/testing/UnitTestBitField.cxx | 20 +++++++++++++++++++ .../raytracing/MeshConnectivityBuilder.cxx | 7 ------- vtkm/rendering/raytracing/MortonCodes.h | 1 - 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index 5a8ca9283..caf883f87 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -256,10 +256,7 @@ private: } KOKKOS_INLINE_FUNCTION - void join(volatile value_type& dst, const volatile value_type& src) const - { - dst = this->Operator(dst, src); - } + void join(value_type& dst, const value_type& src) const { dst = this->Operator(dst, src); } KOKKOS_INLINE_FUNCTION void init(value_type& dst) const diff --git a/vtkm/cont/testing/UnitTestBitField.cxx b/vtkm/cont/testing/UnitTestBitField.cxx index 1d19995c8..66c23be51 100644 --- a/vtkm/cont/testing/UnitTestBitField.cxx +++ b/vtkm/cont/testing/UnitTestBitField.cxx @@ -24,6 +24,25 @@ #include +#if defined(KOKKOS_ENABLE_SYCL) +#define DEVICE_ASSERT_MSG(cond, message) \ + do \ + { \ + if (!(cond)) \ + { \ + return false; \ + } \ + } while (false) + +#define DEVICE_ASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + return false; \ + } \ + } while (false) +#else #define DEVICE_ASSERT_MSG(cond, message) \ do \ { \ @@ -47,6 +66,7 @@ return false; \ } \ } while (false) +#endif // Test with some trailing bits in partial last word: #define NUM_BITS \ diff --git a/vtkm/rendering/raytracing/MeshConnectivityBuilder.cxx b/vtkm/rendering/raytracing/MeshConnectivityBuilder.cxx index 37a6a5a57..c9e79d9c5 100644 --- a/vtkm/rendering/raytracing/MeshConnectivityBuilder.cxx +++ b/vtkm/rendering/raytracing/MeshConnectivityBuilder.cxx @@ -110,8 +110,6 @@ public: { tableOffset = tables.FaceLookUp(3, 0); } - else - printf("Error shape not recognized %d\n", (int)shapeType); return tableOffset; } @@ -282,7 +280,6 @@ public: vtkm::Int32 shapesFaceOffset = tables.FaceLookUp(tables.CellTypeLookUp(shapeId), 0); if (shapesFaceOffset == -1) { - printf("Unsupported Shape Type %d\n", shapeId); return; } @@ -403,10 +400,6 @@ public: for (segment = 0; index >= Segments[segment + 1]; ++segment) ; - if (segment >= 6) - { - printf("OUT OF BOUDNS %d", (int)index); - } vtkm::Int32 cellFace = SegmentToFace[segment]; // Face relative directions of the diff --git a/vtkm/rendering/raytracing/MortonCodes.h b/vtkm/rendering/raytracing/MortonCodes.h index b35374b2f..fb78db1e5 100644 --- a/vtkm/rendering/raytracing/MortonCodes.h +++ b/vtkm/rendering/raytracing/MortonCodes.h @@ -183,7 +183,6 @@ public: } else { - printf("Unknown shape type %d\n", (int)cellShape.Id); return; } From da731005b3d2eeab0ff5973df63793accc3eeef8 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 9 Feb 2023 11:19:00 -0700 Subject: [PATCH 06/64] Remove unused comments in test --- .../testing/UnitTestArrayExtractComponent.cxx | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx index 8e770364d..9a9ccade4 100644 --- a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx +++ b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx @@ -38,20 +38,12 @@ template void CheckInputArray(const vtkm::cont::ArrayHandle& originalArray, vtkm::CopyFlag allowCopy = vtkm::CopyFlag::Off) { - //std::cout << " Checking input array type " - // << vtkm::cont::TypeToString>() << std::endl; - - //std::cout << " Original array: "; - //vtkm::cont::printSummary_ArrayHandle(originalArray, std::cout); - using FlatVec = vtkm::VecFlat; using ComponentType = typename FlatVec::ComponentType; for (vtkm::IdComponent componentId = 0; componentId < FlatVec::NUM_COMPONENTS; ++componentId) { vtkm::cont::ArrayHandleStride componentArray = vtkm::cont::ArrayExtractComponent(originalArray, componentId, allowCopy); - //std::cout << " Component " << componentId << ": "; - //vtkm::cont::printSummary_ArrayHandle(componentArray, std::cout); auto originalPortal = originalArray.ReadPortal(); auto componentPortal = componentArray.ReadPortal(); @@ -70,12 +62,6 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle& originalArray) { CheckInputArray(originalArray); - //std::cout << " Checking output array type " - // << vtkm::cont::TypeToString>() << std::endl; - - //std::cout << " Original array: "; - //vtkm::cont::printSummary_ArrayHandle(originalArray, std::cout); - vtkm::cont::ArrayHandle outputArray; using FlatVec = vtkm::VecFlat; @@ -115,9 +101,6 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle& originalArray) } } - //std::cout << " Output array: "; - //vtkm::cont::printSummary_ArrayHandle(outputArray, std::cout); - auto inPortal = originalArray.ReadPortal(); auto outPortal = outputArray.ReadPortal(); for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex) From a7679c9e99072bb4aa312ed6c56d6dd161c4020a Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 9 Feb 2023 15:27:09 -0700 Subject: [PATCH 07/64] Add more safety to VecTraits You can often get compile errors when trying to get `Vec` attributes from types that do not define `VecTraits`. This is of particular problem when you create an object like `Vec` with a component that does not define `VecTraits`. Make using these types safer by internally using `SafeVecTraits`, which will gracefully handle types that do not have `VecTraits`. --- vtkm/VecFlat.h | 22 ++++++++++++---------- vtkm/VecFromPortal.h | 3 ++- vtkm/VecTraits.h | 29 ++++++++++++++++++----------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/vtkm/VecFlat.h b/vtkm/VecFlat.h index 01d2b5028..476241881 100644 --- a/vtkm/VecFlat.h +++ b/vtkm/VecFlat.h @@ -22,18 +22,20 @@ namespace internal { template ::HasMultipleComponents> + typename MultipleComponents = + typename vtkm::internal::SafeVecTraits::HasMultipleComponents> struct TotalNumComponents; template struct TotalNumComponents { VTKM_STATIC_ASSERT_MSG( - (std::is_same::IsSizeStatic, vtkm::VecTraitsTagSizeStatic>::value), + (std::is_same::IsSizeStatic, + vtkm::VecTraitsTagSizeStatic>::value), "vtkm::VecFlat can only be used with Vec types with a static number of components."); - using ComponentType = typename vtkm::VecTraits::ComponentType; + using ComponentType = typename vtkm::internal::SafeVecTraits::ComponentType; static constexpr vtkm::IdComponent value = - vtkm::VecTraits::NUM_COMPONENTS * TotalNumComponents::value; + vtkm::internal::SafeVecTraits::NUM_COMPONENTS * TotalNumComponents::value; }; template @@ -43,7 +45,7 @@ struct TotalNumComponents }; template -using FlattenVec = vtkm::Vec::BaseComponentType, +using FlattenVec = vtkm::Vec::BaseComponentType, vtkm::internal::TotalNumComponents::value>; template @@ -62,10 +64,10 @@ VTKM_EXEC_CONT T GetFlatVecComponentImpl(const T& component, } template -VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType +VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type vtkmNotUsed(isBase)) { - using Traits = vtkm::VecTraits; + using Traits = vtkm::internal::SafeVecTraits; using ComponentType = typename Traits::ComponentType; using BaseComponentType = typename Traits::BaseComponentType; @@ -78,7 +80,7 @@ GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type v } // namespace detail template -VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponent( +VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType GetFlatVecComponent( const T& vec, vtkm::IdComponent index) { @@ -112,7 +114,7 @@ VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(const NestedVecType& nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { - using Traits = vtkm::VecTraits; + using Traits = vtkm::internal::SafeVecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; @@ -174,7 +176,7 @@ VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, NestedVecType& nestedVec) { - using Traits = vtkm::VecTraits; + using Traits = vtkm::internal::SafeVecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; diff --git a/vtkm/VecFromPortal.h b/vtkm/VecFromPortal.h index 9906c0e61..268da892b 100644 --- a/vtkm/VecFromPortal.h +++ b/vtkm/VecFromPortal.h @@ -91,7 +91,8 @@ struct VecTraits> using VecType = vtkm::VecFromPortal; using ComponentType = typename VecType::ComponentType; - using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; + using BaseComponentType = + typename vtkm::internal::SafeVecTraits::BaseComponentType; using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents; using IsSizeStatic = vtkm::VecTraitsTagSizeVariable; diff --git a/vtkm/VecTraits.h b/vtkm/VecTraits.h index 1d6cb1c45..440a4ced2 100644 --- a/vtkm/VecTraits.h +++ b/vtkm/VecTraits.h @@ -45,16 +45,20 @@ struct VecTraitsTagSizeVariable namespace internal { -template +// Forward declaration +template +struct SafeVecTraits; + +template struct VecTraitsMultipleComponentChooser { using Type = vtkm::VecTraitsTagMultipleComponents; }; -template <> -struct VecTraitsMultipleComponentChooser<1> +template +struct VecTraitsMultipleComponentChooser<1, ComponentType> { - using Type = vtkm::VecTraitsTagSingleComponent; + using Type = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; }; } // namespace internal @@ -95,7 +99,7 @@ struct VTKM_NEVER_EXPORT VecTraits /// is really just a scalar. /// using HasMultipleComponents = - typename internal::VecTraitsMultipleComponentChooser::Type; + typename internal::VecTraitsMultipleComponentChooser::Type; /// \brief A tag specifying whether the size of this vector is known at compile time. /// @@ -197,7 +201,8 @@ template struct VecReplaceBaseComponentTypeGCC4or5 { using type = - vtkm::Vec::template ReplaceBaseComponentType, Size>; + vtkm::Vec::template ReplaceBaseComponentType, + Size>; }; } // namespace detail @@ -219,7 +224,8 @@ struct VTKM_NEVER_EXPORT VecTraits> /// Similar to ComponentType except that for nested vectors (e.g. Vec, N>), it /// returns the base scalar type at the end of the composition (T in this example). /// - using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; + using BaseComponentType = + typename vtkm::internal::SafeVecTraits::BaseComponentType; /// Number of components in the vector. /// @@ -235,7 +241,7 @@ struct VTKM_NEVER_EXPORT VecTraits> /// when a vector is really just a scalar. /// using HasMultipleComponents = - typename internal::VecTraitsMultipleComponentChooser::Type; + typename internal::VecTraitsMultipleComponentChooser::Type; /// A tag specifying whether the size of this vector is known at compile /// time. If set to \c VecTraitsTagSizeStatic, then \c NUM_COMPONENTS is set. @@ -298,9 +304,10 @@ struct VTKM_NEVER_EXPORT VecTraits> typename detail::VecReplaceBaseComponentTypeGCC4or5::type; #else // !GCC <= 5 template - using ReplaceBaseComponentType = vtkm::Vec< - typename vtkm::VecTraits::template ReplaceBaseComponentType, - Size>; + using ReplaceBaseComponentType = + vtkm::Vec::template ReplaceBaseComponentType, + Size>; #endif ///@} From cdd1dbd7bc0726811407528d246e89065b9487b9 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 6 Feb 2023 06:50:34 -0700 Subject: [PATCH 08/64] Add ArrayHandleRuntimeVec The new `ArrayHandleRuntimeVec` is a fancy `ArrayHandle` allows you to specify a basic array of `Vec`s where the number of components of the `Vec` are not known until runtime. (It can also optionally specify scalars.) The behavior is much like that of `ArrayHandleGroupVecVariable` except that its representation is much more constrained. This constrained representation allows it to be automatically converted to an `ArrayHandleBasic` with the proper `Vec` value type. This allows one part of code (such as a file reader) to create an array with any `Vec` size, and then that array can be fed to an algorithm that expects an `ArrayHandleBasic` of a certain value type. --- docs/changelog/runtime-vec-array.md | 12 + vtkm/VecFromPortal.h | 26 + vtkm/cont/ArrayHandleGroupVecVariable.h | 19 +- vtkm/cont/ArrayHandleRuntimeVec.h | 454 ++++++++++++++++++ vtkm/cont/CMakeLists.txt | 1 + vtkm/cont/testing/CMakeLists.txt | 1 + .../testing/UnitTestArrayExtractComponent.cxx | 86 +++- .../testing/UnitTestArrayHandleRuntimeVec.cxx | 201 ++++++++ .../UnitTestSerializationArrayHandle.cxx | 18 + 9 files changed, 796 insertions(+), 22 deletions(-) create mode 100644 docs/changelog/runtime-vec-array.md create mode 100644 vtkm/cont/ArrayHandleRuntimeVec.h create mode 100644 vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx diff --git a/docs/changelog/runtime-vec-array.md b/docs/changelog/runtime-vec-array.md new file mode 100644 index 000000000..01bbae39e --- /dev/null +++ b/docs/changelog/runtime-vec-array.md @@ -0,0 +1,12 @@ +# Added `ArrayHandleRuntimeVec` to specify vector sizes at runtime. + +The new `ArrayHandleRuntimeVec` is a fancy `ArrayHandle` allows you to +specify a basic array of `Vec`s where the number of components of the `Vec` +are not known until runtime. (It can also optionally specify scalars.) The +behavior is much like that of `ArrayHandleGroupVecVariable` except that its +representation is much more constrained. This constrained representation +allows it to be automatically converted to an `ArrayHandleBasic` with the +proper `Vec` value type. This allows one part of code (such as a file +reader) to create an array with any `Vec` size, and then that array can be +fed to an algorithm that expects an `ArrayHandleBasic` of a certain value +type. diff --git a/vtkm/VecFromPortal.h b/vtkm/VecFromPortal.h index 268da892b..b68468307 100644 --- a/vtkm/VecFromPortal.h +++ b/vtkm/VecFromPortal.h @@ -53,6 +53,18 @@ public: } } + template + VTKM_EXEC_CONT operator vtkm::Vec() const + { + vtkm::Vec result; + this->CopyInto(result); + for (vtkm::IdComponent index = this->NumComponents; index < N; ++index) + { + result[index] = vtkm::TypeTraits::ZeroInitialization(); + } + return result; + } + VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::internal::ArrayPortalValueReference operator[](vtkm::IdComponent index) const @@ -61,6 +73,20 @@ public: index + this->Offset); } + template + VTKM_EXEC_CONT VecFromPortal& operator=(const vtkm::Vec& src) + { + vtkm::IdComponent numComponents = vtkm::Min(N, this->NumComponents); + for (vtkm::IdComponent index = 0; index < numComponents; ++index) + { + this->Portal.Set(index + this->Offset, src[index]); + } + return *this; + } + + VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; } + VTKM_EXEC_CONT vtkm::Id GetOffset() const { return this->Offset; } + private: PortalType Portal; vtkm::IdComponent NumComponents; diff --git a/vtkm/cont/ArrayHandleGroupVecVariable.h b/vtkm/cont/ArrayHandleGroupVecVariable.h index 1c28ab194..98f625301 100644 --- a/vtkm/cont/ArrayHandleGroupVecVariable.h +++ b/vtkm/cont/ArrayHandleGroupVecVariable.h @@ -47,7 +47,7 @@ public: { } - /// Copy constructor for any other ArrayPortalConcatenate with a portal type + /// Copy constructor for any other ArrayPortalGroupVecVariable with a portal type /// that can be copied to this portal type. This allows us to do any type /// casting that the portals do (like the non-const to const cast). VTKM_SUPPRESS_EXEC_WARNINGS @@ -77,12 +77,19 @@ public: VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT - void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const + void Set(vtkm::Id index, const ValueType& value) const { - // The ValueType (VecFromPortal) operates on demand. Thus, if you set - // something in the value, it has already been passed to the array. Perhaps - // we should check to make sure that the value used matches the location - // you are trying to set in the array, but we don't do that. + if ((&value.GetPortal() == &this->ComponentsPortal) && + (value.GetOffset() == this->OffsetsPortal.Get(index))) + { + // The ValueType (VecFromPortal) operates on demand. Thus, if you set + // something in the value, it has already been passed to the array. + } + else + { + // The value comes from somewhere else. Copy data in. + this->Get(index) = value; + } } VTKM_SUPPRESS_EXEC_WARNINGS diff --git a/vtkm/cont/ArrayHandleRuntimeVec.h b/vtkm/cont/ArrayHandleRuntimeVec.h new file mode 100644 index 000000000..af0ae5850 --- /dev/null +++ b/vtkm/cont/ArrayHandleRuntimeVec.h @@ -0,0 +1,454 @@ +//============================================================================ +// 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_ArrayHandleRuntimeVec_h +#define vtk_m_cont_ArrayHandleRuntimeVec_h + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace vtkm +{ +namespace internal +{ + +template +class VTKM_ALWAYS_EXPORT ArrayPortalRuntimeVec +{ +public: + using ComponentType = typename std::remove_const::type; + using ValueType = vtkm::VecFromPortal; + + ArrayPortalRuntimeVec() = default; + + VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ComponentsPortalType& componentsPortal, + vtkm::IdComponent numComponents) + : ComponentsPortal(componentsPortal) + , NumberOfComponents(numComponents) + { + } + + /// Copy constructor for any other ArrayPortalRuntimeVec with a portal type + /// that can be copied to this portal type. This allows us to do any type + /// casting that the portals do (like the non-const to const cast). + template + VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ArrayPortalRuntimeVec& src) + : ComponentsPortal(src.GetComponentsPortal()) + , NumberOfComponents(src.GetNumberOfComponents()) + { + } + + VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const + { + return this->ComponentsPortal.GetNumberOfValues() / this->NumberOfComponents; + } + + VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const + { + return ValueType( + this->ComponentsPortal, this->NumberOfComponents, index * this->NumberOfComponents); + } + + VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const + { + if ((&value.GetPortal() == &this->ComponentsPortal) && + (value.GetOffset() == (index * this->NumberOfComponents))) + { + // The ValueType (VecFromPortal) operates on demand. Thus, if you set + // something in the value, it has already been passed to the array. + } + else + { + // The value comes from somewhere else. Copy data in. + this->Get(index) = value; + } + } + + VTKM_EXEC_CONT const ComponentsPortalType& GetComponentsPortal() const + { + return this->ComponentsPortal; + } + + VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const + { + return this->NumberOfComponents; + } + +private: + ComponentsPortalType ComponentsPortal; + vtkm::IdComponent NumberOfComponents = 0; +}; + +} +} // namespace vtkm::internal + +namespace vtkm +{ +namespace cont +{ + +struct VTKM_ALWAYS_EXPORT StorageTagRuntimeVec +{ +}; + +namespace internal +{ + +template +class Storage, vtkm::cont::StorageTagRuntimeVec> +{ + using ComponentType = typename ComponentsPortal::ValueType; + using ComponentsStorage = + vtkm::cont::internal::Storage; + + using ComponentsArray = vtkm::cont::ArrayHandle; + + VTKM_STATIC_ASSERT_MSG( + (std::is_same::value), + "Used invalid ComponentsPortal type with expected ComponentsStorageTag."); + + struct Info + { + vtkm::IdComponent NumberOfComponents; + }; + + VTKM_CONT static std::vector ComponentsBuffers( + const std::vector& buffers) + { + return std::vector(buffers.begin() + 1, buffers.end()); + } + +public: + using ReadPortalType = + vtkm::internal::ArrayPortalRuntimeVec; + using WritePortalType = + vtkm::internal::ArrayPortalRuntimeVec; + + VTKM_CONT static vtkm::IdComponent GetNumberOfComponents( + const std::vector& buffers) + { + return buffers[0].GetMetaData().NumberOfComponents; + } + + VTKM_CONT static vtkm::Id GetNumberOfValues( + const std::vector& buffers) + { + return ComponentsStorage::GetNumberOfValues(ComponentsBuffers(buffers)) / + GetNumberOfComponents(buffers); + } + + VTKM_CONT static void ResizeBuffers(vtkm::Id numValues, + const std::vector& buffers, + vtkm::CopyFlag preserve, + vtkm::cont::Token& token) + { + ComponentsStorage::ResizeBuffers( + numValues * GetNumberOfComponents(buffers), ComponentsBuffers(buffers), preserve, token); + } + + VTKM_CONT static void Fill(const std::vector&, + const vtkm::VecFromPortal&, + vtkm::Id, + vtkm::Id, + vtkm::cont::Token&) + { + throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleRuntimeVec."); + } + + VTKM_CONT static ReadPortalType CreateReadPortal( + const std::vector& buffers, + vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) + { + return ReadPortalType( + ComponentsStorage::CreateReadPortal(ComponentsBuffers(buffers), device, token), + GetNumberOfComponents(buffers)); + } + + VTKM_CONT static WritePortalType CreateWritePortal( + const std::vector& buffers, + vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) + { + return WritePortalType( + ComponentsStorage::CreateWritePortal(ComponentsBuffers(buffers), device, token), + GetNumberOfComponents(buffers)); + } + + VTKM_CONT static std::vector CreateBuffers( + vtkm::IdComponent numComponents = 1, + const ComponentsArray& componentsArray = ComponentsArray{}) + { + VTKM_LOG_IF_S(vtkm::cont::LogLevel::Warn, + (componentsArray.GetNumberOfValues() % numComponents) != 0, + "Array given to ArrayHandleRuntimeVec has size (" + << componentsArray.GetNumberOfValues() + << ") that is not divisible by the number of components selected (" + << numComponents << ")."); + Info info; + info.NumberOfComponents = numComponents; + return vtkm::cont::internal::CreateBuffers(info, componentsArray); + } + + VTKM_CONT static ComponentsArray GetComponentsArray( + const std::vector& buffers) + { + return ComponentsArray(ComponentsBuffers(buffers)); + } + + VTKM_CONT static void AsArrayHandleBasic( + const std::vector& buffers, + vtkm::cont::ArrayHandle& dest) + { + if (GetNumberOfComponents(buffers) != 1) + { + throw vtkm::cont::ErrorBadType( + "Attempted to pull a scalar array from an ArrayHandleRuntime that does not hold scalars."); + } + dest = GetComponentsArray(buffers); + } + + template + VTKM_CONT static void AsArrayHandleBasic( + const std::vector& buffers, + vtkm::cont::ArrayHandle, vtkm::cont::StorageTagBasic>& dest) + { + if (GetNumberOfComponents(buffers) != N) + { + throw vtkm::cont::ErrorBadType( + "Attempted to pull an array of Vecs of the wrong size from an ArrayHandleRuntime."); + } + dest = vtkm::cont::ArrayHandle, vtkm::cont::StorageTagBasic>( + ComponentsBuffers(buffers)); + } + + template + VTKM_CONT static void AsArrayHandleBasic( + const std::vector& buffers, + vtkm::cont::ArrayHandle, NOuter>, vtkm::cont::StorageTagBasic>& + dest) + { + // Flatten the Vec by one level and attempt to get the array handle for that. + vtkm::cont::ArrayHandleBasic> squashedArray; + AsArrayHandleBasic(buffers, squashedArray); + // Now unsquash the array by stealling the buffers and creating an array of the right type + dest = + vtkm::cont::ArrayHandle, NOuter>, vtkm::cont::StorageTagBasic>( + squashedArray.GetBuffers()); + } +}; + +} // namespace internal + +/// \brief Fancy array handle for a basic array with runtime selected vec size. +/// +/// It is sometimes the case that you need to create an array of `Vec`s where +/// the number of components is not known until runtime. This is problematic +/// for normal `ArrayHandle`s because you have to specify the size of the `Vec`s +/// as a template parameter at compile time. `ArrayHandleRuntimeVec` can be used +/// in this case. +/// +/// Note that this version of `ArrayHandle` breaks some of the assumptions +/// about `ArrayHandle` a little bit. Typically, there is exactly one type for +/// every value in the array, and this value is also the same between the +/// control and execution environment. However, this class uses `VecFromPortal` +/// it implement a `Vec`-like class that has a variable number of +/// values, and this type can change between control and execution +/// environments. +/// +/// It is possible to provide an `ArrayHandleBasic` of the same component +/// type as the underlying storage for this array. In this case, the array +/// will be accessed much in the same manner as `ArrayHandleGroupVec`. +/// +/// `ArrayHandleRuntimeVec` also allows you to convert the array to an +/// `ArrayHandleBasic` of the appropriate `Vec` type (or `component` type). +/// A runtime check will be performed to make sure the number of components +/// matches. +/// +template +class ArrayHandleRuntimeVec + : public vtkm::cont::ArrayHandle< + vtkm::VecFromPortal::WritePortalType>, + vtkm::cont::StorageTagRuntimeVec> +{ +public: + VTKM_ARRAY_HANDLE_SUBCLASS( + ArrayHandleRuntimeVec, + (ArrayHandleRuntimeVec), + (vtkm::cont::ArrayHandle< + vtkm::VecFromPortal::WritePortalType>, + vtkm::cont::StorageTagRuntimeVec>)); + +private: + using StorageType = vtkm::cont::internal::Storage; + using ComponentsArrayType = vtkm::cont::ArrayHandle; + +public: + VTKM_CONT + ArrayHandleRuntimeVec(vtkm::IdComponent numComponents, + const ComponentsArrayType& componentsArray = ComponentsArrayType{}) + : Superclass(StorageType::CreateBuffers(numComponents, componentsArray)) + { + } + + VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const + { + return StorageType::GetNumberOfComponents(this->GetBuffers()); + } + + VTKM_CONT vtkm::cont::ArrayHandleBasic GetComponentsArray() const + { + return StorageType::GetComponentsArray(this->GetBuffers()); + } + + ///@{ + /// \brief Converts the array to that of a basic array handle. + /// + /// This method converts the `ArrayHandleRuntimeVec` to a simple `ArrayHandleBasic`. + /// This is useful if the `ArrayHandleRuntimeVec` is passed to a routine that works + /// on an array of a specific `Vec` size (or scalars). After a runtime check, the + /// array can be converted to a typical array and used as such. + template + void AsArrayHandleBasic(vtkm::cont::ArrayHandle& array) const + { + StorageType::AsArrayHandleBasic(this->GetBuffers(), array); + } + + template + ArrayType AsArrayHandleBasic() const + { + ArrayType array; + this->AsArrayHandleBasic(array); + return array; + } + ///@} +}; + +/// \c make_ArrayHandleRuntimeVec is convenience function to generate an +/// ArrayHandleRuntimeVec. It takes in an ArrayHandle of values and an +/// array handle of offsets and returns an array handle with consecutive +/// entries grouped in a Vec. +/// +template +VTKM_CONT vtkm::cont::ArrayHandleRuntimeVec make_ArrayHandleRuntimeVec( + vtkm::IdComponent numComponents, + const vtkm::cont::ArrayHandle& componentsArray) +{ + return vtkm::cont::ArrayHandleRuntimeVec(numComponents, componentsArray); +} + +namespace internal +{ + +template <> +struct ArrayExtractComponentImpl +{ + template + auto operator()(const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy) const + { + using ComponentType = typename T::ComponentType; + vtkm::cont::ArrayHandleRuntimeVec array{ src }; + constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat::NUM_COMPONENTS; + vtkm::cont::ArrayHandleStride::BaseComponentType> dest = + ArrayExtractComponentImpl{}( + array.GetComponentsArray(), componentIndex % NUM_SUB_COMPONENTS, allowCopy); + + // Adjust stride and offset to expectations of grouped values + const vtkm::IdComponent numComponents = array.GetNumberOfComponents(); + return vtkm::cont::ArrayHandleStride::BaseComponentType>( + dest.GetBasicArray(), + dest.GetNumberOfValues() / numComponents, + dest.GetStride() * numComponents, + dest.GetOffset() + (dest.GetStride() * (componentIndex / NUM_SUB_COMPONENTS)), + dest.GetModulo(), + dest.GetDivisor()); + } +}; + +} // namespace internal + +} +} // namespace vtkm::cont + +//============================================================================= +// Specializations of serialization related classes +/// @cond SERIALIZATION +namespace vtkm +{ +namespace cont +{ + +template +struct SerializableTypeString> +{ + static VTKM_CONT const std::string& Get() + { + static std::string name = "AH_RuntimeVec<" + SerializableTypeString::Get() + ">"; + return name; + } +}; + +template +struct SerializableTypeString> + : SerializableTypeString> +{ +}; + +} +} // vtkm::cont + +namespace mangled_diy_namespace +{ + +template +struct Serialization> +{ +private: + using Type = vtkm::cont::ArrayHandleRuntimeVec; + using BaseType = vtkm::cont::ArrayHandle; + +public: + static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) + { + vtkmdiy::save(bb, Type(obj).GetNumberOfComponents()); + vtkmdiy::save(bb, Type(obj).GetComponentsArray()); + } + + static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) + { + vtkm::IdComponent numComponents; + vtkm::cont::ArrayHandleBasic componentArray; + + vtkmdiy::load(bb, numComponents); + vtkmdiy::load(bb, componentArray); + + obj = vtkm::cont::make_ArrayHandleRuntimeVec(numComponents, componentArray); + } +}; + +template +struct Serialization> + : Serialization> +{ +}; + +} // diy +/// @endcond SERIALIZATION + +#endif //vtk_m_cont_ArrayHandleRuntimeVec_h diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 761652c22..53b5308d5 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -38,6 +38,7 @@ set(headers ArrayHandleRandomStandardNormal.h ArrayHandleRandomUniformBits.h ArrayHandleRandomUniformReal.h + ArrayHandleRuntimeVec.h ArrayHandleSOA.h ArrayHandleStride.h ArrayHandleSwizzle.h diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index ef4c4e566..be6595f0c 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -85,6 +85,7 @@ set(unit_tests_device UnitTestArrayHandleRandomStandardNormal.cxx UnitTestArrayHandleRandomUniformReal.cxx UnitTestArrayHandleRecombineVec.cxx + UnitTestArrayHandleRuntimeVec.cxx UnitTestArrayHandleSOA.cxx UnitTestArrayHandleSwizzle.cxx UnitTestArrayHandleTransform.cxx diff --git a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx index 9a9ccade4..07da16d8b 100644 --- a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx +++ b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -34,39 +35,79 @@ namespace constexpr vtkm::Id ARRAY_SIZE = 10; +template +vtkm::IdComponent GetTotalNumComponents(const T& vec) +{ + using VTraits = vtkm::VecTraits; + if (std::is_same::value) + { + return VTraits::GetNumberOfComponents(vec); + } + else + { + return VTraits::GetNumberOfComponents(vec) * + GetTotalNumComponents(VTraits::GetComponent(vec, 0)); + } +} + +// VecFlat.h has something similar, but it only works with static Vec sizes. It might make sense +// to move this somewhere else later +template +struct GetVecFlatIndexImpl +{ + template + VTKM_CONT BaseComponentType operator()(const VecType& vec, vtkm::IdComponent index) const + { + const vtkm::IdComponent subSize = GetTotalNumComponents(vec[0]); + return (*this)(vec[index / subSize], index % subSize); + } + + VTKM_CONT BaseComponentType operator()(const BaseComponentType& component, + vtkm::IdComponent index) const + { + VTKM_ASSERT(index == 0); + return component; + } +}; + +template +auto GetVecFlatIndex(const T& vec, vtkm::IdComponent index) +{ + return GetVecFlatIndexImpl::BaseComponentType>{}(vec, index); +} + template void CheckInputArray(const vtkm::cont::ArrayHandle& originalArray, vtkm::CopyFlag allowCopy = vtkm::CopyFlag::Off) { - using FlatVec = vtkm::VecFlat; - using ComponentType = typename FlatVec::ComponentType; - for (vtkm::IdComponent componentId = 0; componentId < FlatVec::NUM_COMPONENTS; ++componentId) + auto originalPortal = originalArray.ReadPortal(); + using ComponentType = typename vtkm::VecTraits::BaseComponentType; + const vtkm::IdComponent numComponents = GetTotalNumComponents(originalPortal.Get(0)); + for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId) { vtkm::cont::ArrayHandleStride componentArray = vtkm::cont::ArrayExtractComponent(originalArray, componentId, allowCopy); - auto originalPortal = originalArray.ReadPortal(); auto componentPortal = componentArray.ReadPortal(); VTKM_TEST_ASSERT(originalPortal.GetNumberOfValues() == componentPortal.GetNumberOfValues()); for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex) { - auto originalValue = vtkm::make_VecFlat(originalPortal.Get(arrayIndex)); + auto originalValue = GetVecFlatIndex(originalPortal.Get(arrayIndex), componentId); ComponentType componentValue = componentPortal.Get(arrayIndex); - VTKM_TEST_ASSERT(test_equal(originalValue[componentId], componentValue)); + VTKM_TEST_ASSERT(test_equal(originalValue, componentValue)); } } } template -void CheckOutputArray(const vtkm::cont::ArrayHandle& originalArray) +void CheckOutputArray( + const vtkm::cont::ArrayHandle& originalArray, + const vtkm::cont::ArrayHandle& outputArray = vtkm::cont::ArrayHandle{}) { CheckInputArray(originalArray); - vtkm::cont::ArrayHandle outputArray; - - using FlatVec = vtkm::VecFlat; - using ComponentType = typename FlatVec::ComponentType; - constexpr vtkm::IdComponent numComponents = FlatVec::NUM_COMPONENTS; + using ComponentType = typename vtkm::VecTraits::BaseComponentType; + const vtkm::IdComponent numComponents = GetTotalNumComponents(originalArray.ReadPortal().Get(0)); // Extract all the stride arrays first, and then allocate them later. This tests to // to make sure that the independent allocation of all the extracted arrays are consistent @@ -105,11 +146,12 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle& originalArray) auto outPortal = outputArray.ReadPortal(); for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex) { - FlatVec inValue = vtkm::make_VecFlat(inPortal.Get(arrayIndex)); - FlatVec outValue = vtkm::make_VecFlat(outPortal.Get(arrayIndex)); + auto inValue = inPortal.Get(arrayIndex); + auto outValue = outPortal.Get(arrayIndex); for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId) { - VTKM_TEST_ASSERT(test_equal(inValue[componentId], outValue[numComponents - componentId - 1])); + VTKM_TEST_ASSERT(test_equal(GetVecFlatIndex(inValue, componentId), + GetVecFlatIndex(outValue, numComponents - componentId - 1))); } } } @@ -161,9 +203,10 @@ void DoTest() { std::cout << "ArrayHandleGroupVec" << std::endl; vtkm::cont::ArrayHandle array; - array.Allocate(ARRAY_SIZE * 2); + array.Allocate(ARRAY_SIZE * 4); SetPortal(array.WritePortal()); CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<2>(array)); + CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<4>(array)); } { @@ -185,6 +228,17 @@ void DoTest() CheckInputArray(vtkm::cont::make_ArrayHandleExtractComponent(compositeArray, 1)); } + { + std::cout << "ArrayHandleRuntimeVec" << std::endl; + vtkm::cont::ArrayHandle array; + array.Allocate(ARRAY_SIZE * 4); + SetPortal(array.WritePortal()); + CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(2, array), + vtkm::cont::ArrayHandleRuntimeVec(2)); + CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(4, array), + vtkm::cont::ArrayHandleRuntimeVec(4)); + } + { std::cout << "ArrayHandleCartesianProduct" << std::endl; vtkm::cont::ArrayHandle array0; diff --git a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx new file mode 100644 index 000000000..a56a9d27a --- /dev/null +++ b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx @@ -0,0 +1,201 @@ +//============================================================================ +// 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 + +namespace +{ + +constexpr vtkm::Id ARRAY_SIZE = 10; + +struct UnusualType +{ + vtkm::Id X; +}; + +} // anonymous namespace + +namespace detail +{ + +template <> +struct TestValueImpl +{ + VTKM_EXEC_CONT UnusualType operator()(vtkm::Id index) const + { + return { TestValue(index, decltype(UnusualType::X){}) }; + } +}; + +template <> +struct TestEqualImpl +{ + VTKM_EXEC_CONT bool operator()(UnusualType value1, + UnusualType value2, + vtkm::Float64 tolerance) const + { + return test_equal(value1.X, value2.X, tolerance); + } +}; + +} // namespace detail + +namespace +{ + +struct PassThrough : vtkm::worklet::WorkletMapField +{ + using ControlSignature = void(FieldIn, FieldOut); + using ExecutionSignature = void(_1, _2); + + template + VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const + { + outValue = inValue; + } +}; + +template +struct TestRuntimeVecAsInput +{ + template + VTKM_CONT void operator()(ComponentType) const + { + using ValueType = vtkm::Vec; + + vtkm::cont::ArrayHandle baseArray; + baseArray.Allocate(ARRAY_SIZE * NUM_COMPONENTS); + SetPortal(baseArray.WritePortal()); + + vtkm::cont::ArrayHandleRuntimeVec runtimeVecArray(NUM_COMPONENTS, baseArray); + VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE, + "Group array reporting wrong array size."); + + vtkm::cont::ArrayHandle resultArray; + + vtkm::cont::Invoker{}(PassThrough{}, runtimeVecArray, resultArray); + + VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE, "Got bad result array size."); + + //verify that the control portal works + vtkm::Id totalIndex = 0; + auto resultPortal = resultArray.ReadPortal(); + for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index) + { + const ValueType result = resultPortal.Get(index); + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + const ComponentType expectedValue = TestValue(totalIndex, ComponentType()); + VTKM_TEST_ASSERT(test_equal(result[componentIndex], expectedValue), + "Result array got wrong value."); + totalIndex++; + } + } + + //verify that you can get the data as a basic array + vtkm::cont::ArrayHandle> flatComponents; + runtimeVecArray.AsArrayHandleBasic(flatComponents); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatComponents, runtimeVecArray)); + + vtkm::cont::ArrayHandle, NUM_COMPONENTS>> + nestedComponents; + runtimeVecArray.AsArrayHandleBasic(nestedComponents); + auto flatPortal = flatComponents.ReadPortal(); + auto nestedPortal = nestedComponents.ReadPortal(); + for (vtkm::Id index = 0; index < flatPortal.GetNumberOfValues(); ++index) + { + VTKM_TEST_ASSERT(test_equal(vtkm::make_VecFlat(flatPortal.Get(index)), + vtkm::make_VecFlat(nestedPortal.Get(index)))); + } + + runtimeVecArray.ReleaseResources(); + } +}; + +template +struct TestRuntimeVecAsOutput +{ + template + VTKM_CONT void operator()(ComponentType) const + { + using ValueType = vtkm::Vec; + + vtkm::cont::ArrayHandle baseArray; + baseArray.Allocate(ARRAY_SIZE); + SetPortal(baseArray.WritePortal()); + + vtkm::cont::ArrayHandle resultArray; + + vtkm::cont::ArrayHandleRuntimeVec runtimeVecArray(NUM_COMPONENTS, resultArray); + + vtkm::cont::Invoker{}(PassThrough{}, baseArray, runtimeVecArray); + + VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE, + "Group array reporting wrong array size."); + + VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE * NUM_COMPONENTS, + "Got bad result array size."); + + //verify that the control portal works + vtkm::Id totalIndex = 0; + auto resultPortal = resultArray.ReadPortal(); + for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index) + { + const ValueType expectedValue = TestValue(index, ValueType()); + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + const ComponentType result = resultPortal.Get(totalIndex); + VTKM_TEST_ASSERT(test_equal(result, expectedValue[componentIndex]), + "Result array got wrong value."); + totalIndex++; + } + } + } +}; + +void Run() +{ + using HandleTypesToTest = + vtkm::List; + using ScalarTypesToTest = vtkm::List; + + std::cout << "-------------------------------------------" << std::endl; + std::cout << "Testing ArrayHandleRuntimeVec(3) as Input" << std::endl; + vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<3>(), HandleTypesToTest()); + + std::cout << "-------------------------------------------" << std::endl; + std::cout << "Testing ArrayHandleRuntimeVec(4) as Input" << std::endl; + vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<4>(), HandleTypesToTest()); + + std::cout << "-------------------------------------------" << std::endl; + std::cout << "Testing ArrayHandleRuntimeVec(2) as Output" << std::endl; + vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<2>(), ScalarTypesToTest()); + + std::cout << "-------------------------------------------" << std::endl; + std::cout << "Testing ArrayHandleRuntimeVec(3) as Output" << std::endl; + vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<3>(), ScalarTypesToTest()); + + std::cout << "-------------------------------------------" << std::endl; + std::cout << "Testing ArrayHandleRuntimeVec(3) as Input with unusual type" << std::endl; + TestRuntimeVecAsInput<3>{}(UnusualType{}); +} + +} // anonymous namespace + +int UnitTestArrayHandleRuntimeVec(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(Run, argc, argv); +} diff --git a/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx b/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx index 93afbf170..30bdcb04e 100644 --- a/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx +++ b/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -303,6 +304,20 @@ struct TestArrayHandleGroupVecVariable } }; +struct TestArrayHandleRuntimeVec +{ + template + void operator()(T) const + { + auto numComps = RandomValue::Make(1, 5); + auto flat = RandomArrayHandle::Make(ArraySize * numComps); + auto array = vtkm::cont::make_ArrayHandleRuntimeVec(numComps, flat); + RunTest(array); + // TODO: Add this back once UnknownArrayHandle supports ArrayHandleRuntimeVec more fully. + //RunTest(MakeTestUnknownArrayHandle(array)); + } +}; + void TestArrayHandleIndex() { auto size = RandomValue::Make(2, 10); @@ -413,6 +428,9 @@ void TestArrayHandleSerialization() std::cout << "Testing ArrayHandleGroupVecVariable\n"; vtkm::testing::Testing::TryTypes(TestArrayHandleGroupVecVariable(), TestTypesList()); + std::cout << "Testing ArrayHandleRuntimeVec\n"; + vtkm::testing::Testing::TryTypes(TestArrayHandleRuntimeVec(), TestTypesList()); + std::cout << "Testing ArrayHandleIndex\n"; TestArrayHandleIndex(); From 88004132c3fb38956f62a84045ba1641a236b517 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 16 Feb 2023 11:26:04 -0700 Subject: [PATCH 09/64] Compile UnitTestAbort.cxx with a normal C++ compiler `UnitTestAbort.cxx` does not touch any code that needs to be compiled on the device, so you do not need a device compiler. Use the standard C++ compiler instead. --- vtkm/cont/testing/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index ef4c4e566..dd0bc072b 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -123,7 +123,7 @@ if(TARGET vtkm_filter_field_conversion) endif() if(TARGET vtkm_filter_contour) - list(APPEND unit_tests_device + list(APPEND unit_tests UnitTestAbort.cxx ) endif() From 504d241b44ac17cdea83d976a3223eff406cf93d Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 16 Feb 2023 12:46:34 -0700 Subject: [PATCH 10/64] Correct documentation about `ArrayHandle`s with `Vec`-like values --- vtkm/cont/ArrayHandleGroupVecVariable.h | 16 +++++++++------- vtkm/cont/ArrayHandleRecombineVec.h | 12 +++++++----- vtkm/cont/ArrayHandleRuntimeVec.h | 16 +++++++++------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/vtkm/cont/ArrayHandleGroupVecVariable.h b/vtkm/cont/ArrayHandleGroupVecVariable.h index 98f625301..d7d512b09 100644 --- a/vtkm/cont/ArrayHandleGroupVecVariable.h +++ b/vtkm/cont/ArrayHandleGroupVecVariable.h @@ -244,13 +244,15 @@ public: /// it contains three values of Vec-like objects with the data [0,1,2,3], /// [4,5], and [6,7,8]. /// -/// Note that this version of \c ArrayHandle breaks some of the assumptions -/// about \c ArrayHandle a little bit. Typically, there is exactly one type for -/// every value in the array, and this value is also the same between the -/// control and execution environment. However, this class uses \c -/// VecFromPortal it implement a Vec-like class that has a variable number of -/// values, and this type can change between control and execution -/// environments. +/// Note that caution should be used with `ArrayHandleRuntimeVec` because the +/// size of the `Vec` values is not known at compile time. Thus, the value +/// type of this array is forced to a special `VecFromPortal` class that can cause +/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` +/// expression does not exist. Furthermore, new variables of type `VecFromPortal` +/// cannot be created. This means that simple operators like `+` will not work +/// because they require an intermediate object to be created. (Equal operators +/// like `+=` do work because they are given an existing variable to place the +/// output.) /// /// The offsets array is often derived from a list of sizes for each of the /// entries. You can use the convenience function \c diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index cb5f6bf80..f99303a95 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -15,8 +15,6 @@ #include #include -#include - #include namespace vtkm @@ -586,9 +584,13 @@ public: /// /// Note that caution should be used with `ArrayHandleRecombineVec` because the /// size of the `Vec` values is not known at compile time. Thus, the value -/// type of this array is forced to a `VecVariable`, which can cause surprises -/// if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` expression -/// does not exist. +/// type of this array is forced to a special `RecombineVec` class that can cause +/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` +/// expression does not exist. Furthermore, new variables of type `RecombineVec` +/// cannot be created. This means that simple operators like `+` will not work +/// because they require an intermediate object to be created. (Equal operators +/// like `+=` do work because they are given an existing variable to place the +/// output.) /// template class ArrayHandleRecombineVec diff --git a/vtkm/cont/ArrayHandleRuntimeVec.h b/vtkm/cont/ArrayHandleRuntimeVec.h index af0ae5850..67012d79d 100644 --- a/vtkm/cont/ArrayHandleRuntimeVec.h +++ b/vtkm/cont/ArrayHandleRuntimeVec.h @@ -262,13 +262,15 @@ public: /// as a template parameter at compile time. `ArrayHandleRuntimeVec` can be used /// in this case. /// -/// Note that this version of `ArrayHandle` breaks some of the assumptions -/// about `ArrayHandle` a little bit. Typically, there is exactly one type for -/// every value in the array, and this value is also the same between the -/// control and execution environment. However, this class uses `VecFromPortal` -/// it implement a `Vec`-like class that has a variable number of -/// values, and this type can change between control and execution -/// environments. +/// Note that caution should be used with `ArrayHandleRuntimeVec` because the +/// size of the `Vec` values is not known at compile time. Thus, the value +/// type of this array is forced to a special `VecFromPortal` class that can cause +/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` +/// expression does not exist. Furthermore, new variables of type `VecFromPortal` +/// cannot be created. This means that simple operators like `+` will not work +/// because they require an intermediate object to be created. (Equal operators +/// like `+=` do work because they are given an existing variable to place the +/// output.) /// /// It is possible to provide an `ArrayHandleBasic` of the same component /// type as the underlying storage for this array. In this case, the array From 6bfb0cedc50cbacd56b65bc0dd99f488b9d11c20 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 16 Feb 2023 15:25:56 -0500 Subject: [PATCH 11/64] kokkos: disable volatile when kokkos >= 3.7 (cherry picked from commit c32e67aa6d394c2267f95bb1306fe705b12bfc13) --- .../kokkos/internal/DeviceAdapterAlgorithmKokkos.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index caf883f87..e29ba78e4 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -32,6 +32,12 @@ VTKM_THIRDPARTY_POST_INCLUDE #include +#ifdef KOKKOS_VERSION_MAJOR> 3 || (KOKKOS_VERSION_MAJOR == 3 && KOKKOS_VERSION_MINOR >= 7) +#define __MAYBE_VOLATILE +#else +#define __MAYBE_VOLATILE volatile +#endif + namespace vtkm { namespace internal @@ -256,7 +262,10 @@ private: } KOKKOS_INLINE_FUNCTION - void join(value_type& dst, const value_type& src) const { dst = this->Operator(dst, src); } + void join(__MAYBE_VOLATILE value_type& dst, const __MAYBE_VOLATILE value_type& src) const + { + dst = this->Operator(dst, src); + } KOKKOS_INLINE_FUNCTION void init(value_type& dst) const @@ -784,4 +793,6 @@ public: } } // namespace vtkm::cont +#undef __MAYBE_VOLATILE + #endif //vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h From 36912c16dc346bd451bac6b0194d9337a2ed0ce8 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Fri, 17 Feb 2023 20:29:38 -0500 Subject: [PATCH 12/64] kokkos: disable volatile when kokkos >= 3.7 --- .../kokkos/internal/DeviceAdapterAlgorithmKokkos.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index e29ba78e4..013ddb045 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -32,12 +32,13 @@ VTKM_THIRDPARTY_POST_INCLUDE #include -#ifdef KOKKOS_VERSION_MAJOR> 3 || (KOKKOS_VERSION_MAJOR == 3 && KOKKOS_VERSION_MINOR >= 7) -#define __MAYBE_VOLATILE +#if KOKKOS_VERSION_MAJOR > 3 || (KOKKOS_VERSION_MAJOR == 3 && KOKKOS_VERSION_MINOR >= 7) +#define VTKM_VOLATILE #else -#define __MAYBE_VOLATILE volatile +#define VTKM_VOLATILE volatile #endif + namespace vtkm { namespace internal @@ -262,7 +263,7 @@ private: } KOKKOS_INLINE_FUNCTION - void join(__MAYBE_VOLATILE value_type& dst, const __MAYBE_VOLATILE value_type& src) const + void join(VTKM_VOLATILE value_type& dst, const VTKM_VOLATILE value_type& src) const { dst = this->Operator(dst, src); } @@ -793,6 +794,6 @@ public: } } // namespace vtkm::cont -#undef __MAYBE_VOLATILE +#undef VTKM_VOLATILE #endif //vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h From 2ac236fe215b246332a1cdc5282203ba897e4dde Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Fri, 17 Feb 2023 20:56:14 -0500 Subject: [PATCH 13/64] kokkos: disable volatile when kokkos >= 3.7 --- .../kokkos/internal/DeviceAdapterAlgorithmKokkos.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index 98ea39907..b5b6e6a26 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -32,6 +32,13 @@ VTKM_THIRDPARTY_POST_INCLUDE #include +#if KOKKOS_VERSION_MAJOR > 3 || (KOKKOS_VERSION_MAJOR == 3 && KOKKOS_VERSION_MINOR >= 7) +#define VTKM_VOLATILE +#else +#define VTKM_VOLATILE volatile +#endif + + namespace vtkm { namespace internal @@ -256,7 +263,10 @@ private: } KOKKOS_INLINE_FUNCTION - void join(value_type& dst, const value_type& src) const { dst = this->Operator(dst, src); } + void join(VTKM_VOLATILE value_type& dst, const VTKM_VOLATILE value_type& src) const + { + dst = this->Operator(dst, src); + } KOKKOS_INLINE_FUNCTION void init(value_type& dst) const @@ -791,4 +801,6 @@ public: } } // namespace vtkm::cont +#undef VTKM_VOLATILE + #endif //vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h From f6b087689cbc578900dfe6315d3835eb7dd42ff3 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Wed, 15 Feb 2023 16:28:29 -0500 Subject: [PATCH 14/64] release: update version and License --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 4c47c9c77..58561b095 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ VTKm License Version 2.0 ======================================================================== -Copyright (c) 2014-2022 +Copyright (c) 2014-2023 Kitware Inc., National Technology & Engineering Solutions of Sandia, LLC (NTESS), UT-Battelle, LLC., From dd79a487a72b5e149a993f992012cabe0a1c0514 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Wed, 15 Feb 2023 16:27:57 -0500 Subject: [PATCH 15/64] release: 2.0.0 release notes --- docs/changelog/2.0/release-notes.md | 75 ++++++++++++++++++++ docs/changelog/document-field-index-order.md | 10 --- docs/changelog/fix-filter-pass-fields.md | 26 ------- docs/changelog/fix-pass-coords.md | 9 --- docs/changelog/vtkm-abort.md | 22 ------ 5 files changed, 75 insertions(+), 67 deletions(-) delete mode 100644 docs/changelog/document-field-index-order.md delete mode 100644 docs/changelog/fix-filter-pass-fields.md delete mode 100644 docs/changelog/fix-pass-coords.md delete mode 100644 docs/changelog/vtkm-abort.md diff --git a/docs/changelog/2.0/release-notes.md b/docs/changelog/2.0/release-notes.md index 2b74e09ec..0eeeae37c 100644 --- a/docs/changelog/2.0/release-notes.md +++ b/docs/changelog/2.0/release-notes.md @@ -21,10 +21,13 @@ VTK-m 2.0 Release Notes - Attach compressed ZFP data as WholeDataSet field 4. [Execution Environment](#Execution-Environment) - Removed ExecutionWholeArray class + - Add initial support for aborting execution 5. [Worklets and Filters](#Worklets-and-Filters) - Correct particle density filter output field - Rename NewFilter base classes to Filter - Fix handling of cell fields in Tube filter + - Fix setting fields to pass in Filter when setting mode + - Respect Filter::PassCoordinateSystem flag in filters creating coordinate systems. 6. [Build](#Build) - More performance test options - Output complete list of libraries for external Makefiles @@ -32,6 +35,7 @@ VTK-m 2.0 Release Notes 7. [Other](#Other) - Expose the Variant helper class - Fix VTKM_LOG_SCOPE + - Clarify field index ordering in Doxygen # Core @@ -240,6 +244,29 @@ that `ExecutionWholeArray` had was that it provided an subscript operator (somewhat incorrectly). Thus, any use of '[..]' to index the array portal have to be changed to use the `Get` method. +## Add initial support for aborting execution + +VTK-m now has preliminary support for aborting execution. The per-thread instances of +`RuntimeDeviceTracker` have a functor called `AbortChecker`. This functor can be set using +`RuntimeDeviceTracker::SetAbortChecker()` and cleared by `RuntimeDeviceTracker::ClearAbortChecker()` +The abort checker functor should return `true` if an abort is requested for the thread, +otherwise, it should return `false`. + +Before launching a new task, `TaskExecute` calls the functor to see if an abort is requested, +and If so, throws an exception of type `vtkm::cont::ErrorUserAbort`. + +Any code that wants to use the abort feature, should set an appropriate `AbortChecker` +functor for the target thread. Then any piece of code that has parts that can execute on +the device should be put under a `try-catch` block. Any clean-up that is required for an +aborted execution should be handled in a `catch` block that handles exceptions of type +`vtkm::cont::ErrorUserAbort`. + +The limitation of this implementation is that it is control-side only. The check for abort +is done before launching a new device task. Once execution has begun on the device, there is +currently no way to abort that. Therefore, this feature is only useful for aborting code +that is made up of several smaller device task launches (Which is the case for most +worklets and filters in VTK-m) + # Worklets and Filters ## Correct particle density filter output field @@ -282,6 +309,43 @@ would also get around some problems with the implementation that was removed here when mixing polylines with other cell types and degenerate lines.) +## Fix setting fields to pass in `Filter` when setting mode + +The `Filter` class has several version of the `SetFieldsToPass` method that +works in conjunction with the `FieldSelection` object to specify which +fields are mapped. For example, the user might have code like this to pass +all fields except those named `pointvar` and `cellvar`: + +``` cpp + filter.SetFieldsToPass({ "pointvar", "cellvar" }, + vtkm::filter::FieldSelection::Mode::Exclude); +``` + +This previously worked by implicitly creating a `FieldSelection` object +using the `std::initializer_list` filled with the 2 strings. This would +then be passed to the `SetFieldsToPass` method, which would capture the +`FieldSelection` object and change the mode. + +This stopped working in a recent change to `FieldSelection` where each +entry is given its own mode. With this new class, the `FieldSelection` +constructor would capture each field in the default mode (`Select`) and +then change the default mode to `Exclude`. However, the already set modes +kept their `Select` status, which is not what is intended. + +This behavior is fixed by adding `SetFieldToPass` overloads that capture +both the `initializer_list` and the `Mode` and then constructs the +`FieldSelection` correctly. + +## Respect `Filter::PassCoordinateSystem` flag in filters creating coordinate systems + +The `Filter` class has a `PassCoordinateSystem` flag that specifies whether +coordinate systems should be passed regardless of whether the associated +field is passed. However, if a filter created its output with the +`CreateResultCoordinateSystem` method this flag was ignored, and the +provided coordinate system was always passed. This might not be what the +user intended, so this method has been fixed to first check the +`PassCoordinateSystem` flag before setting the coordinates on the output. + # Build ## More performance test options @@ -375,3 +439,14 @@ This was not what was happening. The second log message was being printed immediately after the first. This is because the scope was taken inside of the `LogScope` method. The macro has been rewritten to put the tracking in the right scope. + +## Clarify field index ordering in Doxygen + +The fields in a `DataSet` are indexed from `0` to `GetNumberOfFields() - 1`. +It is natural to assume that the fields will be indexed in the order that +they are added, but they are not. Rather, the indexing is arbitrary and can +change any time a field is added to the dataset. + +To make this more clear, Doxygen documentation is added to the `DataSet` +methods to inform users to not make any assumptions about the order of +field indexing. diff --git a/docs/changelog/document-field-index-order.md b/docs/changelog/document-field-index-order.md deleted file mode 100644 index 53b00d318..000000000 --- a/docs/changelog/document-field-index-order.md +++ /dev/null @@ -1,10 +0,0 @@ -# Clarify field index ordering in Doxygen - -The fields in a `DataSet` are indexed from `0` to `GetNumberOfFields() - 1`. -It is natural to assume that the fields will be indexed in the order that -they are added, but they are not. Rather, the indexing is arbitrary and can -change any time a field is added to the dataset. - -To make this more clear, Doxygen documentation is added to the `DataSet` -methods to inform users to not make any assumptions about the order of -field indexing. diff --git a/docs/changelog/fix-filter-pass-fields.md b/docs/changelog/fix-filter-pass-fields.md deleted file mode 100644 index 5854a1fe4..000000000 --- a/docs/changelog/fix-filter-pass-fields.md +++ /dev/null @@ -1,26 +0,0 @@ -# Fix setting fields to pass in `Filter` when setting mode - -The `Filter` class has several version of the `SetFieldsToPass` method that -works in conjunction with the `FieldSelection` object to specify which -fields are mapped. For example, the user might have code like this to pass -all fields except those named `pointvar` and `cellvar`: - -``` cpp - filter.SetFieldsToPass({ "pointvar", "cellvar" }, - vtkm::filter::FieldSelection::Mode::Exclude); -``` - -This previously worked by implicitly creating a `FieldSelection` object -using the `std::initializer_list` filled with the 2 strings. This would -then be passed to the `SetFieldsToPass` method, which would capture the -`FieldSelection` object and change the mode. - -This stopped working in a recent change to `FieldSelection` where each -entry is given its own mode. With this new class, the `FieldSelection` -constructor would capture each field in the default mode (`Select`) and -then change the default mode to `Exclude`. However, the already set modes -kept their `Select` status, which is not what is intended. - -This behavior is fixed by adding `SetFieldToPass` overloads that capture -both the `initializer_list` and the `Mode` and then constructs the -`FieldSelection` correctly. diff --git a/docs/changelog/fix-pass-coords.md b/docs/changelog/fix-pass-coords.md deleted file mode 100644 index a95a04da8..000000000 --- a/docs/changelog/fix-pass-coords.md +++ /dev/null @@ -1,9 +0,0 @@ -# Respect `Filter::PassCoordinateSystem` flag in filters creating coordinate systems - -The `Filter` class has a `PassCoordinateSystem` flag that specifies whether -coordinate systems should be passed regardless of whether the associated -field is passed. However, if a filter created its output with the -`CreateResultCoordinateSystem` method this flag was ignored, and the -provided coordinate system was always passed. This might not be what the -user intended, so this method has been fixed to first check the -`PassCoordinateSystem` flag before setting the coordinates on the output. diff --git a/docs/changelog/vtkm-abort.md b/docs/changelog/vtkm-abort.md deleted file mode 100644 index 8bd25c7d0..000000000 --- a/docs/changelog/vtkm-abort.md +++ /dev/null @@ -1,22 +0,0 @@ -# Add initial support for aborting execution - -VTK-m now has preliminary support for aborting execution. The per-thread instances of -`RuntimeDeviceTracker` have a functor called `AbortChecker`. This functor can be set using -`RuntimeDeviceTracker::SetAbortChecker()` and cleared by `RuntimeDeviceTracker::ClearAbortChecker()` -The abort checker functor should return `true` if an abort is requested for the thread, -otherwise, it should return `false`. - -Before launching a new task, `TaskExecute` calls the functor to see if an abort is requested, -and If so, throws an exception of type `vtkm::cont::ErrorUserAbort`. - -Any code that wants to use the abort feature, should set an appropriate `AbortChecker` -functor for the target thread. Then any piece of code that has parts that can execute on -the device should be put under a `try-catch` block. Any clean-up that is required for an -aborted execution should be handled in a `catch` block that handles exceptions of type -`vtkm::cont::ErrorUserAbort`. - -The limitation of this implementation is that it is control-side only. The check for abort -is done before launching a new device task. Once execution has begun on the device, there is -currently no way to abort that. Therefore, this feature is only useful for aborting code -that is made up of several smaller device task launches (Which is the case for most -worklets and filters in VTK-m) From cfd6d3fbe534343d217c2dce47a46763692db0ec Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Wed, 15 Feb 2023 16:30:00 -0500 Subject: [PATCH 16/64] 2.0.0 is our 15th official release of VTK-m. The major changes to VTK-m from (previous release) can be found in: docs/changelog/2.0.0/release-notes.md --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index e88e20067..227cea215 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.0-rc1 +2.0.0 From 04013b9924baeb6d73ae875c99baf557b2838794 Mon Sep 17 00:00:00 2001 From: Sean Miller Date: Wed, 26 Oct 2022 16:48:11 -0500 Subject: [PATCH 17/64] Add sorting implementation using thrust Co-authored-by: Thomas Gibson --- .../internal/DeviceAdapterAlgorithmKokkos.h | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index b5b6e6a26..2c9e1cf07 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -38,6 +38,10 @@ VTKM_THIRDPARTY_POST_INCLUDE #define VTKM_VOLATILE volatile #endif +#if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) +#include +#include +#endif namespace vtkm { @@ -771,6 +775,103 @@ public: SortImpl(values, comp, typename std::is_scalar::type{}); } +protected: + // Used to define valid operators in Thrust (only used if thrust is enabled) + template + struct ThrustSortByKeySupport : std::false_type + { + }; + + // Kokkos currently (11/10/2022) does not support a sort_by_key operator + // so instead we are using thrust if and only if HIP or CUDA are the backends for Kokkos +#if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) + + // Valid thrust instantiations + template <> + struct ThrustSortByKeySupport : std::true_type + { + template + using Operator = thrust::less; + }; + template <> + struct ThrustSortByKeySupport : std::true_type + { + template + using Operator = thrust::greater; + }; + + template + VTKM_CONT static void SortByKeyImpl(vtkm::cont::ArrayHandle& keys, + vtkm::cont::ArrayHandle& values, + BinaryCompare, + std::true_type, + std::true_type, + std::true_type) + { + vtkm::cont::Token token; + auto keys_portal = keys.PrepareForInPlace(vtkm::cont::DeviceAdapterTagKokkos{}, token); + auto values_portal = values.PrepareForInPlace(vtkm::cont::DeviceAdapterTagKokkos{}, token); + + kokkos::internal::KokkosViewExec keys_view(keys_portal.GetArray(), + keys_portal.GetNumberOfValues()); + kokkos::internal::KokkosViewExec values_view(values_portal.GetArray(), + values_portal.GetNumberOfValues()); + using ThrustOperator = typename ThrustSortByKeySupport::template Operator; + + thrust::device_ptr keys_begin(keys_view.data()); + thrust::device_ptr keys_end(keys_view.data() + keys_view.size()); + thrust::device_ptr values_begin(values_view.data()); + thrust::sort_by_key(keys_begin, keys_end, values_begin, ThrustOperator()); + } + +#endif + + template + VTKM_CONT static void SortByKeyImpl(vtkm::cont::ArrayHandle& keys, + vtkm::cont::ArrayHandle& values, + BinaryCompare binary_compare, + ValidKeys, + ValidValues, + ValidCompare) + { + // Default to general algorithm + Superclass::SortByKey(keys, values, binary_compare); + } + +public: + template + VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle& keys, + vtkm::cont::ArrayHandle& values) + { + // Make sure not to use the general algorithm here since + // it will use Sort algorithm instead of SortByKey + SortByKey(keys, values, internal::DefaultCompareFunctor()); + } + + template + VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle& keys, + vtkm::cont::ArrayHandle& values, + BinaryCompare binary_compare) + { + // If T or U are not scalar types, or the BinaryCompare is not supported + // then the general algorithm is called, otherwise we will run thrust + SortByKeyImpl(keys, + values, + binary_compare, + typename std::is_scalar::type{}, + typename std::is_scalar::type{}, + typename ThrustSortByKeySupport::type{}); + } + + //---------------------------------------------------------------------------- + VTKM_CONT static void Synchronize() { vtkm::cont::kokkos::internal::GetExecutionSpaceInstance().fence(); From 5a72275ed80c110b404dd2adee5bc798d32c90cb Mon Sep 17 00:00:00 2001 From: Thomas Gibson Date: Thu, 8 Dec 2022 21:14:29 -0600 Subject: [PATCH 18/64] Rewrite sorting specialization using std::enable_if_t --- .../internal/DeviceAdapterAlgorithmKokkos.h | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index 2c9e1cf07..d47ecf44e 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -776,37 +776,18 @@ public: } protected: - // Used to define valid operators in Thrust (only used if thrust is enabled) - template - struct ThrustSortByKeySupport : std::false_type - { - }; - // Kokkos currently (11/10/2022) does not support a sort_by_key operator // so instead we are using thrust if and only if HIP or CUDA are the backends for Kokkos #if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) - // Valid thrust instantiations - template <> - struct ThrustSortByKeySupport : std::true_type - { - template - using Operator = thrust::less; - }; - template <> - struct ThrustSortByKeySupport : std::true_type - { - template - using Operator = thrust::greater; - }; - template - VTKM_CONT static void SortByKeyImpl(vtkm::cont::ArrayHandle& keys, - vtkm::cont::ArrayHandle& values, - BinaryCompare, - std::true_type, - std::true_type, - std::true_type) + VTKM_CONT static std::enable_if_t<(std::is_same::value || + std::is_same::value)> + SortByKeyImpl(vtkm::cont::ArrayHandle& keys, + vtkm::cont::ArrayHandle& values, + BinaryCompare, + std::true_type, + std::true_type) { vtkm::cont::Token token; auto keys_portal = keys.PrepareForInPlace(vtkm::cont::DeviceAdapterTagKokkos{}, token); @@ -816,12 +797,19 @@ protected: keys_portal.GetNumberOfValues()); kokkos::internal::KokkosViewExec values_view(values_portal.GetArray(), values_portal.GetNumberOfValues()); - using ThrustOperator = typename ThrustSortByKeySupport::template Operator; thrust::device_ptr keys_begin(keys_view.data()); thrust::device_ptr keys_end(keys_view.data() + keys_view.size()); thrust::device_ptr values_begin(values_view.data()); - thrust::sort_by_key(keys_begin, keys_end, values_begin, ThrustOperator()); + + if (std::is_same::value) + { + thrust::sort_by_key(keys_begin, keys_end, values_begin, thrust::less()); + } + else + { + thrust::sort_by_key(keys_begin, keys_end, values_begin, thrust::greater()); + } } #endif @@ -832,14 +820,12 @@ protected: class StorageU, class BinaryCompare, typename ValidKeys, - typename ValidValues, - typename ValidCompare> + typename ValidValues> VTKM_CONT static void SortByKeyImpl(vtkm::cont::ArrayHandle& keys, vtkm::cont::ArrayHandle& values, BinaryCompare binary_compare, ValidKeys, - ValidValues, - ValidCompare) + ValidValues) { // Default to general algorithm Superclass::SortByKey(keys, values, binary_compare); @@ -866,8 +852,7 @@ public: values, binary_compare, typename std::is_scalar::type{}, - typename std::is_scalar::type{}, - typename ThrustSortByKeySupport::type{}); + typename std::is_scalar::type{}); } //---------------------------------------------------------------------------- From e6f63a807dc0a78c0e595c6aa30dfd6be0b54cd3 Mon Sep 17 00:00:00 2001 From: Sean Miller Date: Mon, 12 Dec 2022 11:53:30 -0600 Subject: [PATCH 19/64] Adding CMake tweaks to turn off thrust algorithms if thrust is not detected. --- CMake/VTKmDeviceAdapters.cmake | 12 ++++++++++++ CMakeLists.txt | 1 + .../kokkos/internal/DeviceAdapterAlgorithmKokkos.h | 4 ++-- vtkm/internal/CMakeLists.txt | 1 + vtkm/internal/Configure.h.in | 4 ++++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CMake/VTKmDeviceAdapters.cmake b/CMake/VTKmDeviceAdapters.cmake index bbecd18fc..8c66b055e 100644 --- a/CMake/VTKmDeviceAdapters.cmake +++ b/CMake/VTKmDeviceAdapters.cmake @@ -357,6 +357,18 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm_kokkos) add_library(vtkm_kokkos_hip INTERFACE) set_property(TARGET vtkm_kokkos_hip PROPERTY EXPORT_NAME kokkos_hip) install(TARGETS vtkm_kokkos_hip EXPORT ${VTKm_EXPORT_NAME}) + + # Make sure rocthrust is available if requested + # If it is not available, warn the user and continue with thrust disabled + if(${VTKm_ENABLE_KOKKOS_THRUST}) + find_package(rocthrust) + if(${rocthrust_FOUND}) + message(STATUS "Kokkos HIP enabled with rocthrust support") + else() + set(VTKm_ENABLE_KOKKOS_THRUST OFF CACHE BOOL "Enable thrust within Kokkos algorithms" FORCE) + message(WARNING "Kokkos HIP enabled, but rocthrust not found. Install rocthrust for improved performance.") + endif() + endif() endif() add_library(vtkm_kokkos INTERFACE IMPORTED GLOBAL) diff --git a/CMakeLists.txt b/CMakeLists.txt index 725199cc4..ebfe20d8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ endmacro () # Configurable Options vtkm_option(VTKm_ENABLE_CUDA "Enable Cuda support" OFF) vtkm_option(VTKm_ENABLE_KOKKOS "Enable Kokkos support" OFF) +vtkm_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" ON) vtkm_option(VTKm_ENABLE_OPENMP "Enable OpenMP support" OFF) vtkm_option(VTKm_ENABLE_TBB "Enable TBB support" OFF) vtkm_option(VTKm_ENABLE_RENDERING "Enable rendering library" ON) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index d47ecf44e..6ccf13a09 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -38,7 +38,7 @@ VTKM_THIRDPARTY_POST_INCLUDE #define VTKM_VOLATILE volatile #endif -#if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) +#if defined(VTKM_ENABLE_KOKKOS_THRUST) #include #include #endif @@ -778,7 +778,7 @@ public: protected: // Kokkos currently (11/10/2022) does not support a sort_by_key operator // so instead we are using thrust if and only if HIP or CUDA are the backends for Kokkos -#if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) +#if defined(VTKM_ENABLE_KOKKOS_THRUST) template VTKM_CONT static std::enable_if_t<(std::is_same::value || diff --git a/vtkm/internal/CMakeLists.txt b/vtkm/internal/CMakeLists.txt index 88f7622f8..8e6989c3a 100755 --- a/vtkm/internal/CMakeLists.txt +++ b/vtkm/internal/CMakeLists.txt @@ -21,6 +21,7 @@ set(VTKM_USE_64BIT_IDS ${VTKm_USE_64BIT_IDS}) set(VTKM_ENABLE_CUDA ${VTKm_ENABLE_CUDA}) set(VTKM_ENABLE_KOKKOS ${VTKm_ENABLE_KOKKOS}) +set(VTKM_ENABLE_KOKKOS_THRUST ${VTKm_ENABLE_KOKKOS_THRUST}) set(VTKM_ENABLE_OPENMP ${VTKm_ENABLE_OPENMP}) set(VTKM_ENABLE_TBB ${VTKm_ENABLE_TBB}) diff --git a/vtkm/internal/Configure.h.in b/vtkm/internal/Configure.h.in index f290d8e39..6e0bf524b 100644 --- a/vtkm/internal/Configure.h.in +++ b/vtkm/internal/Configure.h.in @@ -300,6 +300,10 @@ #ifndef VTKM_KOKKOS_HIP #cmakedefine VTKM_KOKKOS_HIP #endif +// Mark if Kokkos algorithms should use thrust +#if defined(VTKM_KOKKOS_HIP) || defined(VTKM_KOKKOS_CUDA) +#cmakedefine VTKM_ENABLE_KOKKOS_THRUST +#endif //Mark if we are building with MPI enabled. #cmakedefine VTKM_ENABLE_MPI From fda475d5bf1eb299ac76a0425881a246016e9326 Mon Sep 17 00:00:00 2001 From: Thomas Gibson Date: Wed, 4 Jan 2023 19:42:47 -0600 Subject: [PATCH 20/64] Rework Thrust CMake options --- CMake/VTKmDeviceAdapters.cmake | 10 +++------- CMakeLists.txt | 6 +++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMake/VTKmDeviceAdapters.cmake b/CMake/VTKmDeviceAdapters.cmake index 8c66b055e..fb13d0bf8 100644 --- a/CMake/VTKmDeviceAdapters.cmake +++ b/CMake/VTKmDeviceAdapters.cmake @@ -359,14 +359,10 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm_kokkos) install(TARGETS vtkm_kokkos_hip EXPORT ${VTKm_EXPORT_NAME}) # Make sure rocthrust is available if requested - # If it is not available, warn the user and continue with thrust disabled - if(${VTKm_ENABLE_KOKKOS_THRUST}) + if(VTKm_ENABLE_KOKKOS_THRUST) find_package(rocthrust) - if(${rocthrust_FOUND}) - message(STATUS "Kokkos HIP enabled with rocthrust support") - else() - set(VTKm_ENABLE_KOKKOS_THRUST OFF CACHE BOOL "Enable thrust within Kokkos algorithms" FORCE) - message(WARNING "Kokkos HIP enabled, but rocthrust not found. Install rocthrust for improved performance.") + if(NOT rocthrust_FOUND) + message(FATAL_ERROR "rocthrust not found. Please set VTKm_ENABLE_KOKKOS_THRUST to OFF.") endif() endif() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index ebfe20d8d..d043d8ec2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,7 +90,6 @@ endmacro () # Configurable Options vtkm_option(VTKm_ENABLE_CUDA "Enable Cuda support" OFF) vtkm_option(VTKm_ENABLE_KOKKOS "Enable Kokkos support" OFF) -vtkm_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" ON) vtkm_option(VTKm_ENABLE_OPENMP "Enable OpenMP support" OFF) vtkm_option(VTKm_ENABLE_TBB "Enable TBB support" OFF) vtkm_option(VTKm_ENABLE_RENDERING "Enable rendering library" ON) @@ -113,6 +112,11 @@ cmake_dependent_option(VTKm_ENABLE_TESTING_LIBRARY "Enable VTKm Testing Library" OFF "NOT VTKm_ENABLE_TESTING;NOT VTKm_ENABLE_BENCHMARKS" ON) mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY) +# By default: Set VTKm_ENABLE_KOKKOS_THRUST to ON if VTKm_ENABLE_KOKKOS is ON, otherwise +# disable it (or if the user explicitly turns this option OFF) +cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" + ON "VTKm_ENABLE_KOKKOS" OFF) + # We may want to make finer controls on whether libraries/modules get built. # VTK uses the concept of groups for its modules vtkm_option(VTKm_BUILD_ALL_LIBRARIES From 802bf80b0fe1d37899351481cdb3b4eb3d7fbf4f Mon Sep 17 00:00:00 2001 From: Thomas Gibson Date: Thu, 5 Jan 2023 14:48:25 -0600 Subject: [PATCH 21/64] CI: Add rocthrust installation step --- .gitlab/ci/docker/ubuntu2004/kokkos-hip/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/docker/ubuntu2004/kokkos-hip/Dockerfile b/.gitlab/ci/docker/ubuntu2004/kokkos-hip/Dockerfile index ebb8501e6..8cffc8b17 100644 --- a/.gitlab/ci/docker/ubuntu2004/kokkos-hip/Dockerfile +++ b/.gitlab/ci/docker/ubuntu2004/kokkos-hip/Dockerfile @@ -14,6 +14,7 @@ RUN apt update && \ ninja-build \ rsync \ ssh \ + rocthrust-dev \ && \ apt clean From 0604f314aabb56c571db2159c67e473c332054df Mon Sep 17 00:00:00 2001 From: Sean Miller Date: Fri, 27 Jan 2023 13:16:55 -0600 Subject: [PATCH 22/64] Fix for building SERIAL unit tests with KOKKOS_HIP/CUDA enabled --- vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h index 6ccf13a09..606309d06 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterAlgorithmKokkos.h @@ -38,7 +38,11 @@ VTKM_THIRDPARTY_POST_INCLUDE #define VTKM_VOLATILE volatile #endif -#if defined(VTKM_ENABLE_KOKKOS_THRUST) +#if defined(VTKM_ENABLE_KOKKOS_THRUST) && (defined(__HIP__) || defined(__CUDA__)) +#define VTKM_USE_KOKKOS_THRUST +#endif + +#if defined(VTKM_USE_KOKKOS_THRUST) #include #include #endif @@ -778,7 +782,7 @@ public: protected: // Kokkos currently (11/10/2022) does not support a sort_by_key operator // so instead we are using thrust if and only if HIP or CUDA are the backends for Kokkos -#if defined(VTKM_ENABLE_KOKKOS_THRUST) +#if defined(VTKM_USE_KOKKOS_THRUST) template VTKM_CONT static std::enable_if_t<(std::is_same::value || From 331a277fe3481aa54a388a67ebf282fb1145b8a2 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 8 Feb 2023 15:16:49 -0700 Subject: [PATCH 23/64] Automatically convert between ArrayHandleBasic and ArrayHandleRuntimeVec The `UnknownArrayHandle` has been updated to allow `ArrayHandleRuntimeVec` to work interchangeably with basic `ArrayHandle`. If an `ArrayHandleRuntimeVec` is put into an `UnknownArrayHandle`, it can be later retrieved as an `ArrayHandleBasic` as long as the base component type matches and it has the correct amount of components. This means that an array can be created as an `ArrayHandleRuntimeVec` and be used with any filters or most other features designed to operate on basic `ArrayHandle`s. Likewise, an array added as a basic `ArrayHandle` can be retrieved in an `ArrayHandleRuntimeVec`. This makes it easier to pull arrays from VTK-m and place them in external structures (such as `vtkDataArray`). --- docs/changelog/runtime-vec-array.md | 11 ++ vtkm/VecFromPortal.h | 9 ++ vtkm/cont/ArrayHandleRuntimeVec.h | 52 ++++++- vtkm/cont/UnknownArrayHandle.cxx | 141 ++++++++++++++--- vtkm/cont/UnknownArrayHandle.h | 144 +++++++++++++++++- .../testing/UnitTestArrayExtractComponent.cxx | 6 +- .../testing/UnitTestArrayHandleRuntimeVec.cxx | 53 ++++++- .../UnitTestSerializationArrayHandle.cxx | 3 +- .../testing/UnitTestUnknownArrayHandle.cxx | 55 +++++++ 9 files changed, 440 insertions(+), 34 deletions(-) diff --git a/docs/changelog/runtime-vec-array.md b/docs/changelog/runtime-vec-array.md index 01bbae39e..a6dd859ee 100644 --- a/docs/changelog/runtime-vec-array.md +++ b/docs/changelog/runtime-vec-array.md @@ -10,3 +10,14 @@ proper `Vec` value type. This allows one part of code (such as a file reader) to create an array with any `Vec` size, and then that array can be fed to an algorithm that expects an `ArrayHandleBasic` of a certain value type. + +The `UnknownArrayHandle` has also been updated to allow +`ArrayHandleRuntimeVec` to work interchangeably with basic `ArrayHandle`. +If an `ArrayHandleRuntimeVec` is put into an `UnknownArrayHandle`, it can +be later retrieved as an `ArrayHandleBasic` as long as the base component +type matches and it has the correct amount of components. This means that +an array can be created as an `ArrayHandleRuntimeVec` and be used with any +filters or most other features designed to operate on basic `ArrayHandle`s. +Likewise, an array added as a basic `ArrayHandle` can be retrieved in an +`ArrayHandleRuntimeVec`. This makes it easier to pull arrays from VTK-m and +place them in external structures (such as `vtkDataArray`). diff --git a/vtkm/VecFromPortal.h b/vtkm/VecFromPortal.h index b68468307..a5b5caca2 100644 --- a/vtkm/VecFromPortal.h +++ b/vtkm/VecFromPortal.h @@ -136,6 +136,15 @@ struct VecTraits> return vector[componentIndex]; } + VTKM_SUPPRESS_EXEC_WARNINGS + VTKM_EXEC_CONT + static void SetComponent(const VecType& vector, + vtkm::IdComponent componentIndex, + const ComponentType& value) + { + vector[componentIndex] = value; + } + VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec& dest) diff --git a/vtkm/cont/ArrayHandleRuntimeVec.h b/vtkm/cont/ArrayHandleRuntimeVec.h index 67012d79d..6006452a9 100644 --- a/vtkm/cont/ArrayHandleRuntimeVec.h +++ b/vtkm/cont/ArrayHandleRuntimeVec.h @@ -26,6 +26,31 @@ namespace vtkm namespace internal { +namespace detail +{ + +template +struct UnrollVecImpl +{ + using type = vtkm::Vec; +}; + +template +struct UnrollVecImpl> +{ + using subtype = typename UnrollVecImpl::type; + using type = vtkm::Vec; +}; + +} // namespace detail + +// A helper class that unrolls a nested `Vec` to a single layer `Vec`. This is similar +// to `vtkm::VecFlat`, except that this only flattens `vtkm::Vec` objects, and not +// any other `Vec`-like objects. The reason is that a `vtkm::Vec` is the same as N +// consecutive `T` objects whereas the same may not be said about other `Vec`-like objects. +template +using UnrollVec = typename detail::UnrollVecImpl::type; + template class VTKM_ALWAYS_EXPORT ArrayPortalRuntimeVec { @@ -115,6 +140,12 @@ class Storage, vtkm::cont::StorageTagRunti using ComponentsStorage = vtkm::cont::internal::Storage; + VTKM_STATIC_ASSERT_MSG( + vtkm::internal::SafeVecTraits::NUM_COMPONENTS == 1, + "ArrayHandleRuntimeVec only supports scalars grouped into a single Vec. Nested Vecs can " + "still be used with ArrayHandleRuntimeVec. The values are treated as flattened (like " + "with VecFlat)."); + using ComponentsArray = vtkm::cont::ArrayHandle; VTKM_STATIC_ASSERT_MSG( @@ -346,11 +377,28 @@ public: /// entries grouped in a Vec. /// template -VTKM_CONT vtkm::cont::ArrayHandleRuntimeVec make_ArrayHandleRuntimeVec( +VTKM_CONT auto make_ArrayHandleRuntimeVec( vtkm::IdComponent numComponents, + const vtkm::cont::ArrayHandle& componentsArray = + vtkm::cont::ArrayHandle{}) +{ + using UnrolledVec = vtkm::internal::UnrollVec; + using ComponentType = typename UnrolledVec::ComponentType; + + // Use some dangerous magic to convert the basic array to its base component and create + // an ArrayHandleRuntimeVec from that. + vtkm::cont::ArrayHandle flatComponents( + componentsArray.GetBuffers()); + + return vtkm::cont::ArrayHandleRuntimeVec( + numComponents * UnrolledVec::NUM_COMPONENTS, flatComponents); +} + +template +VTKM_CONT auto make_ArrayHandleRuntimeVec( const vtkm::cont::ArrayHandle& componentsArray) { - return vtkm::cont::ArrayHandleRuntimeVec(numComponents, componentsArray); + return make_ArrayHandleRuntimeVec(1, componentsArray); } namespace internal diff --git a/vtkm/cont/UnknownArrayHandle.cxx b/vtkm/cont/UnknownArrayHandle.cxx index dde409c17..1c5f1f4ab 100644 --- a/vtkm/cont/UnknownArrayHandle.cxx +++ b/vtkm/cont/UnknownArrayHandle.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -45,12 +46,16 @@ struct AllVecImpl> template using AllVec = typename AllVecImpl::type; +template +using IsBasicStorage = std::is_same; +template +using RemoveBasicStorage = vtkm::ListRemoveIf; + using UnknownSerializationTypes = vtkm::ListAppend, AllVec<3>, AllVec<4>>; -using UnknownSerializationStorage = - vtkm::ListAppend, + vtkm::List, vtkm::cont::StorageTagConstant, @@ -432,30 +437,82 @@ std::string SerializableTypeString::Get() } } // namespace vtkm::cont -namespace mangled_diy_namespace +namespace { -void Serialization::save(BinaryBuffer& bb, - const vtkm::cont::UnknownArrayHandle& obj) +enum struct SerializedArrayType : vtkm::UInt8 +{ + BasicArray = 0, + SpecializedStorage +}; + +struct SaveBasicArray +{ + template + VTKM_CONT void operator()(ComponentType, + mangled_diy_namespace::BinaryBuffer& bb, + const vtkm::cont::UnknownArrayHandle& obj, + bool& saved) + { + // Basic arrays and arrays with compatible layouts can be loaed/saved as an + // ArrayHandleRuntimeVec. Thus, we can load/save them all with one routine. + using ArrayType = vtkm::cont::ArrayHandleRuntimeVec; + if (!saved && obj.CanConvert()) + { + ArrayType array = obj.AsArrayHandle(); + vtkmdiy::save(bb, SerializedArrayType::BasicArray); + vtkmdiy::save(bb, vtkm::cont::TypeToString()); + vtkmdiy::save(bb, array); + saved = true; + } + } +}; + +struct LoadBasicArray +{ + template + VTKM_CONT void operator()(ComponentType, + mangled_diy_namespace::BinaryBuffer& bb, + vtkm::cont::UnknownArrayHandle& obj, + const std::string& componentTypeString, + bool& loaded) + { + if (!loaded && (componentTypeString == vtkm::cont::TypeToString())) + { + vtkm::cont::ArrayHandleRuntimeVec array; + vtkmdiy::load(bb, array); + obj = array; + loaded = true; + } + } +}; + +VTKM_CONT void SaveSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb, + const vtkm::cont::UnknownArrayHandle& obj) { vtkm::IdComponent numComponents = obj.GetNumberOfComponents(); switch (numComponents) { case 1: + vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage); vtkmdiy::save(bb, numComponents); - vtkmdiy::save(bb, obj.ResetTypes()); + vtkmdiy::save(bb, + obj.ResetTypes()); break; case 2: + vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage); vtkmdiy::save(bb, numComponents); - vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationStorage>()); + vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationSpecializedStorage>()); break; case 3: + vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage); vtkmdiy::save(bb, numComponents); - vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationStorage>()); + vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationSpecializedStorage>()); break; case 4: + vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage); vtkmdiy::save(bb, numComponents); - vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationStorage>()); + vtkmdiy::save(bb, obj.ResetTypes, UnknownSerializationSpecializedStorage>()); break; default: throw vtkm::cont::ErrorBadType( @@ -465,16 +522,17 @@ void Serialization::save(BinaryBuffer& bb, } } -void Serialization::load(BinaryBuffer& bb, - vtkm::cont::UnknownArrayHandle& obj) +VTKM_CONT void LoadSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb, + vtkm::cont::UnknownArrayHandle& obj) { vtkm::IdComponent numComponents; vtkmdiy::load(bb, numComponents); - vtkm::cont::UncertainArrayHandle array1; - vtkm::cont::UncertainArrayHandle, UnknownSerializationStorage> array2; - vtkm::cont::UncertainArrayHandle, UnknownSerializationStorage> array3; - vtkm::cont::UncertainArrayHandle, UnknownSerializationStorage> array4; + vtkm::cont::UncertainArrayHandle + array1; + vtkm::cont::UncertainArrayHandle, UnknownSerializationSpecializedStorage> array2; + vtkm::cont::UncertainArrayHandle, UnknownSerializationSpecializedStorage> array3; + vtkm::cont::UncertainArrayHandle, UnknownSerializationSpecializedStorage> array4; switch (numComponents) { @@ -499,4 +557,53 @@ void Serialization::load(BinaryBuffer& bb, } } +} // anonymous namespace + +namespace mangled_diy_namespace +{ + +void Serialization::save(BinaryBuffer& bb, + const vtkm::cont::UnknownArrayHandle& obj) +{ + bool saved = false; + + // First, try serializing basic arrays (which we can do for any Vec size). + vtkm::ListForEach(SaveBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, saved); + + // If that did not work, try one of the specialized arrays. + if (!saved) + { + SaveSpecializedArray(bb, obj); + } +} + +void Serialization::load(BinaryBuffer& bb, + vtkm::cont::UnknownArrayHandle& obj) +{ + SerializedArrayType arrayType; + vtkmdiy::load(bb, arrayType); + + switch (arrayType) + { + case SerializedArrayType::BasicArray: + { + std::string componentTypeString; + vtkmdiy::load(bb, componentTypeString); + bool loaded = false; + vtkm::ListForEach( + LoadBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, componentTypeString, loaded); + if (!loaded) + { + throw vtkm::cont::ErrorInternal("Failed to load basic array. Unexpected buffer values."); + } + break; + } + case SerializedArrayType::SpecializedStorage: + LoadSpecializedArray(bb, obj); + break; + default: + throw vtkm::cont::ErrorInternal("Got inappropriate enumeration value for loading array."); + } +} + } // namespace mangled_diy_namespace diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 1f8c2b0e6..88b40590f 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,14 @@ void UnknownAHDelete(void* mem) delete arrayHandle; } +template +const std::vector& UnknownAHBuffers(void* mem) +{ + using AH = vtkm::cont::ArrayHandle; + AH* arrayHandle = reinterpret_cast(mem); + return arrayHandle->GetBuffers(); +} + template void* UnknownAHNewInstance() { @@ -259,6 +268,9 @@ struct VTKM_CONT_EXPORT UnknownAHContainer using DeleteType = void(void*); DeleteType* DeleteFunction; + using BuffersType = const std::vector&(void*); + BuffersType* Buffers; + using NewInstanceType = void*(); NewInstanceType* NewInstance; @@ -383,6 +395,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle::BaseComponentType>()) , DeleteFunction(detail::UnknownAHDelete) + , Buffers(detail::UnknownAHBuffers) , NewInstance(detail::UnknownAHNewInstance) , NewInstanceBasic(detail::UnknownAHNewInstanceBasic) , NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic) @@ -646,13 +659,10 @@ public: #ifdef VTKM_MSVC VTKM_DEPRECATED_SUPPRESS_BEGIN #endif - ///@{ - /// Returns this array cast appropriately and stored in the given `ArrayHandle` type. - /// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type. - /// Use the `CanConvert` method to determine if the array can be returned with the given type. - /// + +private: template - VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle& array) const + VTKM_CONT void BaseAsArrayHandle(vtkm::cont::ArrayHandle& array) const { using ArrayType = vtkm::cont::ArrayHandle; if (!this->IsType()) @@ -664,6 +674,21 @@ public: array = *reinterpret_cast(this->Container->ArrayHandlePointer); } +public: + ///@{ + /// Returns this array cast appropriately and stored in the given `ArrayHandle` type. + /// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type. + /// Use the `CanConvert` method to determine if the array can be returned with the given type. + /// + template + VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle& array) const + { + this->BaseAsArrayHandle(array); + } + + template + VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle& array) const; + template VTKM_CONT void AsArrayHandle( vtkm::cont::ArrayHandle>& array) const; @@ -677,6 +702,26 @@ public: this->AsArrayHandle()); } + template + VTKM_CONT void AsArrayHandle( + vtkm::cont::ArrayHandle& array) const + { + using BaseT = typename T::ComponentType; + if (this->IsStorageType() && this->IsBaseComponentType()) + { + // Reinterpret the basic array as components, and then wrap that in a runtime vec + // with the correct amount of components. + vtkm::cont::ArrayHandle basicArray( + this->Container->Buffers(this->Container->ArrayHandlePointer)); + array = + vtkm::cont::ArrayHandleRuntimeVec(this->GetNumberOfComponentsFlat(), basicArray); + } + else + { + this->BaseAsArrayHandle(array); + } + } + template VTKM_CONT ArrayType AsArrayHandle() const { @@ -916,6 +961,19 @@ struct UnknownArrayHandleCanConvert } }; +template +struct UnknownArrayHandleCanConvert +{ + VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const + { + using UnrolledVec = vtkm::internal::UnrollVec; + return (array.IsType>() || + (array.IsStorageType() && + array.IsBaseComponentType() && + UnrolledVec::NUM_COMPONENTS == array.GetNumberOfComponentsFlat())); + } +}; + template struct UnknownArrayHandleCanConvert> { @@ -946,10 +1004,22 @@ struct UnknownArrayHandleCanConvert> } }; +template +struct UnknownArrayHandleCanConvert +{ + VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const + { + using BaseComponentType = typename T::ComponentType; + return (array.IsType>() || + (array.IsStorageType() && + array.IsBaseComponentType())); + } +}; + } // namespace detail template -VTKM_CONT bool UnknownArrayHandle::CanConvert() const +VTKM_CONT inline bool UnknownArrayHandle::CanConvert() const { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); @@ -960,6 +1030,66 @@ VTKM_CONT bool UnknownArrayHandle::CanConvert() const namespace detail { +template ::ComponentType>::NUM_COMPONENTS> +struct UnknownArrayHandleRuntimeVecAsBasic +{ + VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*, + const detail::UnknownAHContainer*, + vtkm::cont::ArrayHandle&) const + { + // This version only gets called if T contains a `Vec`-like object that is not a strict `Vec`. + // This is rare but could happen. In this case, the type cannot be stored in an + // `ArrayHandleRuntimeVec` and therefore the load can never happen, so just ignore. + return false; + } +}; + +template +struct UnknownArrayHandleRuntimeVecAsBasic +{ + VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle* self, + const detail::UnknownAHContainer* container, + vtkm::cont::ArrayHandle& array) const + { + using UnrolledVec = vtkm::internal::UnrollVec; + using ComponentType = typename UnrolledVec::ComponentType; + if (self->IsStorageType() && + self->IsBaseComponentType() && + UnrolledVec::NUM_COMPONENTS == self->GetNumberOfComponentsFlat()) + { + // Pull out the components array out of the buffers. The array might not match exactly + // the array put in, but the buffer should still be consistent with the array (which works + // because the size of a basic array is based on the number of bytes in the buffer). + using RuntimeVecType = typename vtkm::cont::ArrayHandleRuntimeVec::ValueType; + using StorageRuntimeVec = + vtkm::cont::internal::Storage; + StorageRuntimeVec::AsArrayHandleBasic(container->Buffers(container->ArrayHandlePointer), + array); + return true; + } + else + { + return false; + } + } +}; + +} // namespace detail + +template +VTKM_CONT inline void UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle& array) const +{ + if (!detail::UnknownArrayHandleRuntimeVecAsBasic{}(this, this->Container.get(), array)) + { + this->BaseAsArrayHandle(array); + } +} + +namespace detail +{ + struct UnknownArrayHandleMultiplexerCastTry { template diff --git a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx index 07da16d8b..600408474 100644 --- a/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx +++ b/vtkm/cont/testing/UnitTestArrayExtractComponent.cxx @@ -230,13 +230,13 @@ void DoTest() { std::cout << "ArrayHandleRuntimeVec" << std::endl; - vtkm::cont::ArrayHandle array; + vtkm::cont::ArrayHandle array; array.Allocate(ARRAY_SIZE * 4); SetPortal(array.WritePortal()); CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(2, array), - vtkm::cont::ArrayHandleRuntimeVec(2)); + vtkm::cont::ArrayHandleRuntimeVec(2)); CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(4, array), - vtkm::cont::ArrayHandleRuntimeVec(4)); + vtkm::cont::ArrayHandleRuntimeVec(4)); } { diff --git a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx index a56a9d27a..a2da0ad5a 100644 --- a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx +++ b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx @@ -10,6 +10,7 @@ #include +#include #include #include @@ -64,7 +65,52 @@ struct PassThrough : vtkm::worklet::WorkletMapField template VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const { - outValue = inValue; + vtkm::IdComponent inIndex = 0; + vtkm::IdComponent outIndex = 0; + this->FlatCopy(inValue, inIndex, outValue, outIndex); + } + + template + VTKM_EXEC void FlatCopy(const InValue& inValue, + vtkm::IdComponent& inIndex, + OutValue& outValue, + vtkm::IdComponent& outIndex) const + { + using VTraitsIn = vtkm::internal::SafeVecTraits; + using VTraitsOut = vtkm::internal::SafeVecTraits; + VTraitsOut::SetComponent(outValue, outIndex, VTraitsIn::GetComponent(inValue, inIndex)); + inIndex++; + outIndex++; + } + + template + VTKM_EXEC void FlatCopy(const vtkm::Vec& inValue, + vtkm::IdComponent& inIndex, + OutValue& outValue, + vtkm::IdComponent& outIndex) const + { + VTKM_ASSERT(inIndex == 0); + for (vtkm::IdComponent i = 0; i < InN; ++i) + { + FlatCopy(inValue[i], inIndex, outValue, outIndex); + inIndex = 0; + } + } + + template + VTKM_EXEC void FlatCopy(const InValue& inValue, + vtkm::IdComponent& inIndex, + vtkm::Vec& outValue, + vtkm::IdComponent& outIndex) const + { + VTKM_ASSERT(outIndex == 0); + for (vtkm::IdComponent i = 0; i < OutN; ++i) + { + OutComponent outComponent; + FlatCopy(inValue, inIndex, outComponent, outIndex); + outValue[i] = outComponent; + outIndex = 0; + } } }; @@ -80,7 +126,7 @@ struct TestRuntimeVecAsInput baseArray.Allocate(ARRAY_SIZE * NUM_COMPONENTS); SetPortal(baseArray.WritePortal()); - vtkm::cont::ArrayHandleRuntimeVec runtimeVecArray(NUM_COMPONENTS, baseArray); + auto runtimeVecArray = vtkm::cont::make_ArrayHandleRuntimeVec(NUM_COMPONENTS, baseArray); VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE, "Group array reporting wrong array size."); @@ -108,7 +154,8 @@ struct TestRuntimeVecAsInput //verify that you can get the data as a basic array vtkm::cont::ArrayHandle> flatComponents; runtimeVecArray.AsArrayHandleBasic(flatComponents); - VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatComponents, runtimeVecArray)); + VTKM_TEST_ASSERT(test_equal_ArrayHandles( + flatComponents, vtkm::cont::make_ArrayHandleGroupVec(baseArray))); vtkm::cont::ArrayHandle, NUM_COMPONENTS>> nestedComponents; diff --git a/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx b/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx index 30bdcb04e..7b93ea522 100644 --- a/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx +++ b/vtkm/cont/testing/UnitTestSerializationArrayHandle.cxx @@ -313,8 +313,7 @@ struct TestArrayHandleRuntimeVec auto flat = RandomArrayHandle::Make(ArraySize * numComps); auto array = vtkm::cont::make_ArrayHandleRuntimeVec(numComps, flat); RunTest(array); - // TODO: Add this back once UnknownArrayHandle supports ArrayHandleRuntimeVec more fully. - //RunTest(MakeTestUnknownArrayHandle(array)); + RunTest(MakeTestUnknownArrayHandle(array)); } }; diff --git a/vtkm/cont/testing/UnitTestUnknownArrayHandle.cxx b/vtkm/cont/testing/UnitTestUnknownArrayHandle.cxx index 327da4d4e..036487fd5 100644 --- a/vtkm/cont/testing/UnitTestUnknownArrayHandle.cxx +++ b/vtkm/cont/testing/UnitTestUnknownArrayHandle.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -542,6 +543,57 @@ void TrySetMultiplexerArray() CheckUnknownArray, vtkm::List>(unknownArray, 1); } +template +void TryConvertRuntimeVec() +{ + using BasicArrayType = vtkm::cont::ArrayHandle; + using BasicComponentType = typename vtkm::VecFlat::ComponentType; + constexpr vtkm::IdComponent numFlatComponents = vtkm::VecFlat::NUM_COMPONENTS; + using RuntimeArrayType = vtkm::cont::ArrayHandleRuntimeVec; + + std::cout << " Get basic array as ArrayHandleRuntimeVec" << std::endl; + BasicArrayType inputArray; + inputArray.Allocate(ARRAY_SIZE); + SetPortal(inputArray.WritePortal()); + + vtkm::cont::UnknownArrayHandle unknownWithBasic{ inputArray }; + VTKM_TEST_ASSERT(unknownWithBasic.GetNumberOfComponentsFlat() == numFlatComponents); + + VTKM_TEST_ASSERT(unknownWithBasic.CanConvert()); + RuntimeArrayType runtimeArray = unknownWithBasic.AsArrayHandle(); + + // Hack to convert the array handle to a flat array to make it easy to check the runtime array + vtkm::cont::ArrayHandle> flatInput{ inputArray.GetBuffers() }; + VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatInput, runtimeArray)); + + std::cout << " Get ArrayHandleRuntimeVec as basic array" << std::endl; + vtkm::cont::UnknownArrayHandle unknownWithRuntimeVec{ runtimeArray }; + VTKM_TEST_ASSERT(unknownWithRuntimeVec.GetNumberOfComponentsFlat() == numFlatComponents); + + VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert()); + VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert()); + BasicArrayType outputArray = unknownWithRuntimeVec.AsArrayHandle(); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(inputArray, outputArray)); +} + +void TryConvertRuntimeVec() +{ + std::cout << " Scalar array." << std::endl; + TryConvertRuntimeVec(); + + std::cout << " Equivalent scalar." << std::endl; + TryConvertRuntimeVec(); + + std::cout << " Basic Vec." << std::endl; + TryConvertRuntimeVec(); + + std::cout << " Vec of Vecs." << std::endl; + TryConvertRuntimeVec>(); + + std::cout << " Vec of Vecs of Vecs." << std::endl; + TryConvertRuntimeVec, 2>>(); +} + struct DefaultTypeFunctor { template @@ -573,6 +625,9 @@ void TestUnknownArrayHandle() std::cout << "Try setting ArrayHandleMultiplexer" << std::endl; TrySetMultiplexerArray(); + + std::cout << "Try converting between ArrayHandleRuntimeVec and basic array" << std::endl; + TryConvertRuntimeVec(); } } // anonymous namespace From 50d4ab5cc18912934c1d7a14c61c72cee3c168ae Mon Sep 17 00:00:00 2001 From: Thomas Gibson Date: Mon, 20 Feb 2023 12:55:58 -0600 Subject: [PATCH 24/64] CMake: VTKm_ENABLE_KOKKOS_THRUST to depend on Kokkos with CUDA or HIP enabled --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d043d8ec2..0065590b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,11 +112,6 @@ cmake_dependent_option(VTKm_ENABLE_TESTING_LIBRARY "Enable VTKm Testing Library" OFF "NOT VTKm_ENABLE_TESTING;NOT VTKm_ENABLE_BENCHMARKS" ON) mark_as_advanced(VTKm_ENABLE_TESTING_LIBRARY) -# By default: Set VTKm_ENABLE_KOKKOS_THRUST to ON if VTKm_ENABLE_KOKKOS is ON, otherwise -# disable it (or if the user explicitly turns this option OFF) -cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" - ON "VTKm_ENABLE_KOKKOS" OFF) - # We may want to make finer controls on whether libraries/modules get built. # VTK uses the concept of groups for its modules vtkm_option(VTKm_BUILD_ALL_LIBRARIES @@ -232,6 +227,11 @@ include(VTKmBuildType) # Include the vtk-m wrappers include(VTKmWrappers) +# By default: Set VTKm_ENABLE_KOKKOS_THRUST to ON if VTKm_ENABLE_KOKKOS is ON, otherwise +# disable it (or if the user explicitly turns this option OFF) +cmake_dependent_option(VTKm_ENABLE_KOKKOS_THRUST "Enable Kokkos thrust support (only valid with CUDA and HIP)" + ON "VTKm_ENABLE_KOKKOS;Kokkos_ENABLE_CUDA OR Kokkos_ENABLE_HIP" OFF) + # Create vtkm_compiler_flags library. This is an interface library that # holds all the C++ compiler flags that are needed for consumers and # when building VTK-m. From 67bf9a966a805adcc4417980cadd4643f88918f3 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Mon, 20 Feb 2023 15:33:00 -0500 Subject: [PATCH 25/64] docker: update kokkos hip image --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 502e9306c..f91d1df65 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,7 +53,7 @@ - .docker_image .ubuntu2004_kokkos: &ubuntu2004_kokkos - image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230125" + image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230220" extends: - .docker_image From 267ee49cb0e81ab614e3daed94b6d87cd1bb33d4 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Tue, 21 Feb 2023 11:01:38 -0500 Subject: [PATCH 26/64] docker: update kokkos hip image --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f91d1df65..421d4af3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,12 +53,12 @@ - .docker_image .ubuntu2004_kokkos: &ubuntu2004_kokkos - image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230220" + image: "kitware/vtkm:ci-ubuntu2004_kokkos-20230125" extends: - .docker_image .ubuntu2004_hip_kokkos: &ubuntu2004_hip_kokkos - image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20230125" + image: "kitware/vtkm:ci-ubuntu2004_hip_kokkos-20230220" extends: - .docker_image From 6cd849d703893be36531c9672b61c27ca3e101be Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Wed, 22 Feb 2023 12:27:53 -0500 Subject: [PATCH 27/64] roadmap: update dates --- docs/ReleaseRoadmap.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/ReleaseRoadmap.md b/docs/ReleaseRoadmap.md index 3dabc2978..51ee42a69 100644 --- a/docs/ReleaseRoadmap.md +++ b/docs/ReleaseRoadmap.md @@ -1,13 +1,13 @@ -# Minor Release Roadmap +# Release Roadmap | Version | Date | Delay (days) | Life-cycle (*planned) | End of Support | | --------- | ------------ | ------- | ----------- | ---------------- | | 1.7.0 | 2021-12-01 | +8 | Long Term | 2022-12-01 | | 1.8.0 | 2022-06-01 | +14 | Long Term | 2023-06-01 | -| 1.9.0 | 2022-09-01 | +41 | Short Term | next release | -| 2.0.0 | 2022-12-01 | | Long Term* | TBD | -| 2.1.0 | 2023-03-01 | | Short Term* | TBD | -| 2.2.0 | 2023-06-01 | | Long Term* | TBD | +| 1.9.0 | 2022-09-01 | +41 | Short Term | 2023-06-01 | +| 2.0.0 | 2022-12-01 | +52 | Long Term* | 2023-12-01 | +| 2.1.0 | 2023-06-01 | | Short Term* | TBD | +| 2.2.0 | 2023-09-01 | | Long Term* | TBD | ## Legend From 85a81d404d42da06c7a5458120b361c5b67e56c7 Mon Sep 17 00:00:00 2001 From: Louis Gombert Date: Wed, 22 Feb 2023 13:18:27 +0100 Subject: [PATCH 28/64] Update tutorial CMakeLists to reflect VTK-m target namespace changes Use target mangling routine to access namespaced targets when building the tutorial internally to VTK-m's build --- tutorial/CMakeLists.txt | 44 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index ac6368a88..b7e749310 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -9,11 +9,10 @@ ##============================================================================ #add the directory that contains the VTK-m config file to the cmake -#path so that our examples can find VTK-m +#path so that our tutorial can find VTK-m #Normally when running CMake, you need to set the VTKm_DIR to #find the VTKmConfig.cmake file. Because we already know where this #file is, we can add the location to look to CMAKE_PREFIX_PATH. - set(CMAKE_PREFIX_PATH ${VTKm_BINARY_DIR}/${VTKm_INSTALL_CONFIG_DIR}) cmake_minimum_required(VERSION 3.12...3.15 FATAL_ERROR) @@ -22,20 +21,41 @@ project(VTKm_tut) #Find the VTK-m package find_package(VTKm REQUIRED QUIET) + +if (VTKm_ENABLE_TUTORIALS) + # VTK-m tutorial targets expect vtkm libraries to be namespaced with the prefix vtkm::. + # However, as the tutorial can also be built as part of the VTK-m code, + # those prefix are not added to the targets (This happens during the + # installation). To workaround this issue here, we create IMPORTED libs linking + # to the vtkm libraries used by the tutorial targets with the expected vtkm:: prefix. + vtkm_module_get_list(module_list) + foreach(tgt IN LISTS module_list) + if(TARGET ${tgt}) + # The reason of creating this phony IMPORTED libraries instead of making + # ALIAS libraries is that ALIAS libraries are GLOBAL whereas IMPORTED are + # local at the directory level where they are created. We do not want these + # phony targets to be visible outside of the tutorial directory. + vtkm_target_mangle(tgt_name_mangled ${tgt}) + add_library("vtkm::${tgt_name_mangled}" INTERFACE IMPORTED) + target_link_libraries("vtkm::${tgt_name_mangled}" INTERFACE ${tgt}) + endif() + endforeach() +endif() + add_executable(io io.cxx) -target_link_libraries(io vtkm_filter vtkm_io) +target_link_libraries(io vtkm::io) add_executable(contour contour.cxx) -target_link_libraries(contour vtkm_filter vtkm_io) +target_link_libraries(contour vtkm::filter_core vtkm::filter_contour vtkm::io) add_executable(contour_two_fields contour_two_fields.cxx) -target_link_libraries(contour_two_fields vtkm_filter vtkm_io) +target_link_libraries(contour_two_fields vtkm::filter_core vtkm::filter_contour vtkm::io) add_executable(two_filters two_filters.cxx) -target_link_libraries(two_filters vtkm_filter vtkm_io) +target_link_libraries(two_filters vtkm::filter_core vtkm::filter_contour vtkm::io) add_executable(mag_grad mag_grad.cxx) -target_link_libraries(mag_grad vtkm_filter vtkm_io) +target_link_libraries(mag_grad vtkm::filter_core vtkm::filter_vector_analysis vtkm::io) # Because mag_grad.cxx creates a worklet with code that # runs on a GPU, it needs additional information. vtkm_add_target_information(mag_grad @@ -44,23 +64,23 @@ vtkm_add_target_information(mag_grad if (VTKm_ENABLE_RENDERING) add_executable(rendering rendering.cxx) - target_link_libraries(rendering vtkm_filter vtkm_io vtkm_rendering) + target_link_libraries(rendering vtkm::io vtkm::rendering) endif () add_executable(error_handling error_handling.cxx) -target_link_libraries(error_handling vtkm_filter vtkm_io) +target_link_libraries(error_handling vtkm::filter_core vtkm::filter_contour vtkm::io) add_executable(logging logging.cxx) -target_link_libraries(logging vtkm_filter vtkm_io) +target_link_libraries(logging vtkm::io) add_executable(point_to_cell point_to_cell.cxx) -target_link_libraries(point_to_cell vtkm_cont vtkm_filter vtkm_io) +target_link_libraries(point_to_cell vtkm::worklet vtkm::filter_core vtkm::io) vtkm_add_target_information(point_to_cell DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS DEVICE_SOURCES point_to_cell.cxx) add_executable(extract_edges extract_edges.cxx) -target_link_libraries(extract_edges vtkm_cont vtkm_filter vtkm_io) +target_link_libraries(extract_edges vtkm::cont vtkm::filter_core vtkm::filter_contour vtkm::worklet vtkm::io) vtkm_add_target_information(extract_edges DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS DEVICE_SOURCES extract_edges.cxx) From 3650b9efd91549422bc3e6750b301ae5d42943c6 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 23 Feb 2023 19:14:51 -0500 Subject: [PATCH 29/64] release,docs: add freeze release branch step fixes: #760 --- docs/NewRelease.md.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/NewRelease.md.tmpl b/docs/NewRelease.md.tmpl index 4ce3d2423..2c6ab3c96 100644 --- a/docs/NewRelease.md.tmpl +++ b/docs/NewRelease.md.tmpl @@ -40,6 +40,8 @@ $endif\ ## Create update branch +- [ ] Freeze the release branch (In Gitlab VTK-m page) + - Settings/Repository/Protected Branches: Release; "allowed to push:No one" - [ ] Create update branch `git checkout -b update-to-$(VERSION)` $if(PATCH == 0 and RC == "-rc1")\ - [ ] Bring as a second parent the history of master (Solve conflicts always @@ -104,6 +106,8 @@ $endif\ - [ ] `Do: merge` - Push tags - [ ] `git push origin v$(VERSION)$(RC)` +- [ ] Unfreeze the release branch (In Gitlab VTK-m page) + - Settings/Repository/Protected Branches: Release; "allowed to push: Maintainers" ## Update Spack - [ ] Update Spack package: https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/vtk-m/package.py From 76a9e8d1e83122521891c428848da0598bbd1855 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 23 Feb 2023 19:15:56 -0500 Subject: [PATCH 30/64] ascent,ci: reduce build concurrency level fixes: #757 --- .gitlab/ci/ascent.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/ascent.yml b/.gitlab/ci/ascent.yml index 569fb19b6..0ba546b21 100644 --- a/.gitlab/ci/ascent.yml +++ b/.gitlab/ci/ascent.yml @@ -46,7 +46,7 @@ build:ascent_gcc_cuda: - git-lfs install - git-lfs pull lfs script: - - CTEST_MAX_PARALLELISM=32 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake + - CTEST_MAX_PARALLELISM=8 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake - ctest -VV -S .gitlab/ci/ctest_configure.cmake artifacts: expire_in: 24 hours From ecd4a68ffc6da12f8768ff7db84c6a41b69dc56e Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 23 Feb 2023 19:30:58 -0500 Subject: [PATCH 31/64] cxx,c++: Remove c++14 references - MSVC C++14 support obtained from: https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170 - _MSVC_VER taken from https://stackoverflow.com/a/70630/2420872 fixes: #754 --- README.md | 2 +- docs/CodingConventions.md | 2 +- vtkm/internal/Configure.h.in | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c57e323ed..e477fa343 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ effort. VTK-m Requires: - + C++11 Compiler. VTK-m has been confirmed to work with the following + + C++14 Compiler. VTK-m has been confirmed to work with the following + GCC 5.4+ + Clang 5.0+ + XCode 5.0+ diff --git a/docs/CodingConventions.md b/docs/CodingConventions.md index 6b3cae299..b57645ab0 100644 --- a/docs/CodingConventions.md +++ b/docs/CodingConventions.md @@ -181,7 +181,7 @@ for (auto v : vector) avoided in class, method, and function scopes (fully qualified namespace references are preferred). - + All code must be valid by the C++11 specifications. It must also + + All code must be valid by the C++14 specifications. It must also compile with Microsoft Visual Studio 2015. + New code must include regression tests that will run on the dashboards. diff --git a/vtkm/internal/Configure.h.in b/vtkm/internal/Configure.h.in index f290d8e39..39b578971 100644 --- a/vtkm/internal/Configure.h.in +++ b/vtkm/internal/Configure.h.in @@ -312,12 +312,12 @@ #define VTKM_CUDA_VERSION_MINOR @VTKM_CUDA_VERSION_MINOR@ #endif -#if __cplusplus >= 201103L || \ - ( defined(VTKM_MSVC) && _MSC_VER >= 1900 ) || \ +#if __cplusplus >= 201402L || \ + ( defined(VTKM_MSVC) && _MSC_VER >= 1910 ) || \ ( defined(VTKM_ICC) && defined(__INTEL_CXX11_MODE__) ) -#define VTKM_HAVE_CXX_11 +#define VTKM_HAVE_CXX_14 #else -#error "VTK-m requires at least a C++11 compiler" +#error "VTK-m requires at least a C++14 compiler" #endif //Mark if we have enabled logging. From 25d03abbaa58348f31fd00f2d18c4cf59d61d8a5 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 23 Feb 2023 20:25:27 -0500 Subject: [PATCH 32/64] readme:add spack and gitlab ver badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c57e323ed..cdf5b618e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![GitLab tag](https://img.shields.io/gitlab/v/tag/vtk/vtk-m?color=red&gitlab_url=https%3A%2F%2Fgitlab.kitware.com&include_prereleases&sort=semver) +![Spack version](https://img.shields.io/spack/v/vtk-m.svg) + # VTK-m # VTK-m is a toolkit of scientific visualization algorithms for emerging From 0b4946b9eecd318101b34182840c8fc6df0023f6 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 2 Mar 2023 14:01:11 -0500 Subject: [PATCH 33/64] spock: build kokkos in every vtk-m build --- .gitlab/ci/config/kokkos.sh | 30 ++++++++++++++++++++++++++++++ .gitlab/ci/spock.yml | 33 ++++++++++++--------------------- 2 files changed, 42 insertions(+), 21 deletions(-) create mode 100755 .gitlab/ci/config/kokkos.sh diff --git a/.gitlab/ci/config/kokkos.sh b/.gitlab/ci/config/kokkos.sh new file mode 100755 index 000000000..ec7650a1c --- /dev/null +++ b/.gitlab/ci/config/kokkos.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -x + +WORKDIR="$1" +VERSION="$2" + +shift 2 + +if [ ! -d "$WORKDIR" ] || [ -z "$VERSION" ] +then + echo "[E] missing args: Invoke as .gitlab/ci/config/kokkos.sh [extra_args]" + exit 1 +fi + +# Build and install Kokkos +curl -L "https://github.com/kokkos/kokkos/archive/refs/tags/$VERSION.tar.gz" \ + | tar -C "$WORKDIR" -xzf - + +cmake -S "$WORKDIR/kokkos-$VERSION" -B "$WORKDIR/kokkos_build" \ + "-DCMAKE_BUILD_TYPE:STRING=release" \ + "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache" \ + "-DCMAKE_CXX_STANDARD:STRING=14" \ + "-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON" \ + "-DKokkos_ENABLE_HIP:BOOL=ON" \ + "-DKokkos_ENABLE_HIP_RELOCATABLE_DEVICE_CODE:BOOL=OFF" \ + "-DKokkos_ENABLE_SERIAL:BOOL=ON" \ + $* + +cmake --build "$WORKDIR/kokkos_build" +cmake --install "$WORKDIR/kokkos_build" diff --git a/.gitlab/ci/spock.yml b/.gitlab/ci/spock.yml index 25fefe211..ea0f3fd29 100644 --- a/.gitlab/ci/spock.yml +++ b/.gitlab/ci/spock.yml @@ -1,9 +1,9 @@ # Ad-hoc build that runs in the ECP Hardware, concretely in OLCF Spock. .spock_gcc_hip: variables: - CCACHE_BASEDIR: "/gpfs/alpine/world-shared/csc331/" - CCACHE_DIR: "/gpfs/alpine/world-shared/csc331/vtk-m/ci/ccache" - CUSTOM_CI_BUILDS_DIR: "/gpfs/alpine/world-shared/csc331/vtk-m/ci/runtime" + CCACHE_BASEDIR: "/gpfs/alpine/csc331/scratch/" + CCACHE_DIR: "/gpfs/alpine/csc331/scratch/vbolea/ci/vtk-m/ccache" + CUSTOM_CI_BUILDS_DIR: "/gpfs/alpine/csc331/scratch/vbolea/ci/vtk-m/runtime" # -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it CCACHE_IGNOREOPTIONS: "-isystem=*" @@ -12,35 +12,25 @@ CMAKE_BUILD_TYPE: "RelWithDebInfo" CMAKE_GENERATOR: "Ninja" + CMAKE_PREFIX_PATH: "$CI_BUILDS_DIR/kokkos_install" - # This is needed for the smoke_test, while we use rocm 5 to build VTK-m the - # smoke_test needs 4.5 since Kokkos is built agains rocm 4.5 - LD_LIBRARY_PATH: "/opt/rocm-4.5.0/lib:${LD_LIBRARY_PATH}" - LIBRARY_PATH: "/opt/rocm-4.5.0/lib:${LIBRARY_PATH}" + KOKKOS_OPTS: >- + -DCMAKE_INSTALL_PREFIX:PATH=$CI_BUILDS_DIR/kokkos_install + -DCMAKE_CXX_COMPILER:FILEPATH=/opt/rocm-4.5.0/hip/bin/hipcc + -DKokkos_ARCH_VEGA908:BOOL=ON - # While Kokkos and VTK-m uses ROCm 4.5.0 runtime/sdk, we need to build - # VTK-m with HIPCC from ROCM 5 - CMAKE_HIP_COMPILER: "/opt/rocm-default/llvm/bin/clang++" - Kokkos_CXX_COMPILER: "/opt/rocm-default/llvm/bin/clang++" - CMAKE_HIP_ARCHITECTURES: "gfx908" - - CC: gcc - CXX: g++ # DefApps/default;craype;rocm;gcc should be loaded first JOB_MODULES: >- DefApps/default - craype-accel-amd-gfx90a - rocm/5 + craype-accel-amd-gfx908 + rocm/4.5.0 gcc/10 cmake/3.22 git git-lfs - kokkos/3.5.00 - lsf-tools ninja - spectrum-mpi zstd - VTKM_SETTINGS: kokkos+hip+spock+ccache+no_rendering + VTKM_SETTINGS: kokkos+hip+gfx908+spock+ccache+no_rendering interruptible: true .setup_env_ecpci: &setup_env_ecpci | @@ -62,6 +52,7 @@ build:spock_gcc_hip: - cmake -VV -P .gitlab/ci/config/ccache.cmake - ccache -z - ccache -s + - .gitlab/ci/config/kokkos.sh "$CI_BUILDS_DIR" "3.7.01" $KOKKOS_OPTS - git remote add lfs https://gitlab.kitware.com/vtk/vtk-m.git - git fetch lfs From eaeced7b7289d050cff4c4bfb368ef5d7343cb18 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 2 Mar 2023 14:09:02 -0500 Subject: [PATCH 34/64] spock,ci,olcf: disable not working spock02 --- .gitlab/ci/spock.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/spock.yml b/.gitlab/ci/spock.yml index ea0f3fd29..7d53c14e0 100644 --- a/.gitlab/ci/spock.yml +++ b/.gitlab/ci/spock.yml @@ -41,7 +41,7 @@ build:spock_gcc_hip: stage: build - tags: [spock, shell] + tags: [spock, shell, olcf-spock-shell-02] extends: - .spock_gcc_hip - .run_spock_ci @@ -70,7 +70,7 @@ build:spock_gcc_hip: test:spock_gcc_hip: stage: test - tags: [spock, slurm] + tags: [spock, slurm, olcf-spock-slurm-02] extends: - .spock_gcc_hip - .run_spock_ci From 2af555f6c9923d1e6fb29f91258e9641d3039b0c Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 2 Mar 2023 15:43:23 -0700 Subject: [PATCH 35/64] Simplify serialization of DataSet objects `vtkm::cont::DataSet` is a dynamic object that can hold cell sets and fields of many different types, none of which are known until runtime. This causes a problem with serialization, which has to know what type to compile the serialization for, particularly when unserializing the type at the receiving end. The original implementation "solved" the problem by creating a secondary wrapper object that was templated on types of field arrays and cell sets that might be serialized. This is not a great solution as it punts the problem to algorithm developers. This problem has been completely solved for fields, as it is possible to serialize most types of arrays without knowing their type now. You still need to iterate over every possible `CellSet` type, but there are not that many `CellSet`s that are practically encountered. Thus, there is now a direct implementation of `Serialization` for `DataSet` that covers all the data types you are likely to encounter. The old `SerializableDataSet` has been deprecated. In the unlikely event an algorithm needs to transfer a non-standard type of `CellSet` (such as a permuted cell set), it can use the replacement `DataSetWithCellSetTypes`, which just specifies the cell set types. --- docs/changelog/serialize-dataset.md | 22 ++++++ .../RedistributePoints.cxx | 10 ++- vtkm/cont/DataSet.cxx | 31 ++++++++ vtkm/cont/DataSet.h | 71 +++++++++++++++---- .../testing/UnitTestSerializationDataSet.cxx | 16 ++++- ...stingContourTreeUniformDistributedFilter.h | 12 ++-- 6 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 docs/changelog/serialize-dataset.md diff --git a/docs/changelog/serialize-dataset.md b/docs/changelog/serialize-dataset.md new file mode 100644 index 000000000..a00831ac2 --- /dev/null +++ b/docs/changelog/serialize-dataset.md @@ -0,0 +1,22 @@ +# Simplified serialization of DataSet objects + +`vtkm::cont::DataSet` is a dynamic object that can hold cell sets and +fields of many different types, none of which are known until runtime. This +causes a problem with serialization, which has to know what type to compile +the serialization for, particularly when unserializing the type at the +receiving end. The original implementation "solved" the problem by creating +a secondary wrapper object that was templated on types of field arrays and +cell sets that might be serialized. This is not a great solution as it +punts the problem to algorithm developers. + +This problem has been completely solved for fields, as it is possible to +serialize most types of arrays without knowing their type now. You still +need to iterate over every possible `CellSet` type, but there are not that +many `CellSet`s that are practically encountered. Thus, there is now a +direct implementation of `Serialization` for `DataSet` that covers all the +data types you are likely to encounter. + +The old `SerializableDataSet` has been deprecated. In the unlikely event an +algorithm needs to transfer a non-standard type of `CellSet` (such as a +permuted cell set), it can use the replacement `DataSetWithCellSetTypes`, +which just specifies the cell set types. diff --git a/examples/redistribute_points/RedistributePoints.cxx b/examples/redistribute_points/RedistributePoints.cxx index 33e6f3084..4f5fdf32f 100644 --- a/examples/redistribute_points/RedistributePoints.cxx +++ b/examples/redistribute_points/RedistributePoints.cxx @@ -133,8 +133,7 @@ public: this->Decomposer.fill_bounds(bds, target.gid); auto extractedDS = this->Extract(*block, bds); - // TODO: Need a better way to serialize DataSet. See issue #725. - rp.enqueue(target, vtkm::cont::SerializableDataSet<>(extractedDS)); + rp.enqueue(target, extractedDS); } // clear our dataset. *block = vtkm::cont::DataSet(); @@ -149,10 +148,9 @@ public: auto target = rp.in_link().target(cc); if (rp.incoming(target.gid).size() > 0) { - // TODO: Need a better way to serialize DataSet. See issue #725. - vtkm::cont::SerializableDataSet<> sds; - rp.dequeue(target.gid, sds); - receives.push_back(sds.DataSet); + vtkm::cont::DataSet incomingDS; + rp.dequeue(target.gid, incomingDS); + receives.push_back(incomingDS); numValues += receives.back().GetCoordinateSystem(0).GetNumberOfPoints(); } } diff --git a/vtkm/cont/DataSet.cxx b/vtkm/cont/DataSet.cxx index 34c5b63bf..608de4fc8 100644 --- a/vtkm/cont/DataSet.cxx +++ b/vtkm/cont/DataSet.cxx @@ -8,6 +8,10 @@ // PURPOSE. See the above copyright notice for more information. //============================================================================ +#include +#include +#include +#include #include #include #include @@ -341,3 +345,30 @@ void DataSet::ConvertToExpected() } // namespace cont } // namespace vtkm + + +namespace mangled_diy_namespace +{ + +using SerializedCellSetTypes = vtkm::ListAppend, + vtkm::cont::CellSetStructured<2>, + vtkm::cont::CellSetStructured<3>, + vtkm::cont::CellSetExplicit<>, + vtkm::cont::CellSetSingleType<>, + vtkm::cont::CellSetExtrude>>; +using DefaultDataSetWithCellTypes = vtkm::cont::DataSetWithCellSetTypes; + +void Serialization::save(BinaryBuffer& bb, const vtkm::cont::DataSet& obj) +{ + vtkmdiy::save(bb, DefaultDataSetWithCellTypes{ obj }); +} + +void Serialization::load(BinaryBuffer& bb, vtkm::cont::DataSet& obj) +{ + DefaultDataSetWithCellTypes data; + vtkmdiy::load(bb, data); + obj = data.DataSet; +} + +} // namespace mangled_diy_namespace diff --git a/vtkm/cont/DataSet.h b/vtkm/cont/DataSet.h index 2cef4af8d..c55a193b7 100644 --- a/vtkm/cont/DataSet.h +++ b/vtkm/cont/DataSet.h @@ -420,37 +420,70 @@ namespace vtkm namespace cont { -template -struct SerializableDataSet +/// \brief Specify cell sets to use when serializing a `DataSet`. +/// +/// Usually when serializing a `DataSet`, it uses a fixed set of standard +/// `CellSet` types to serialize. If you are writing an algorithm with a +/// custom `CellSet`, you can specify the `CellSet`(s) as the template +/// parameter for this class (either as a list of `CellSet`s or in a +/// single `vtkm::List` parameter). +/// +template +struct DataSetWithCellSetTypes { - SerializableDataSet() = default; + vtkm::cont::DataSet DataSet; - explicit SerializableDataSet(const vtkm::cont::DataSet& dataset) + DataSetWithCellSetTypes() = default; + + explicit DataSetWithCellSetTypes(const vtkm::cont::DataSet& dataset) : DataSet(dataset) { } - - vtkm::cont::DataSet DataSet; }; + +template +struct DataSetWithCellSetTypes> + : DataSetWithCellSetTypes +{ + using DataSetWithCellSetTypes::DataSetWithCellSetTypes; +}; + +template +struct VTKM_DEPRECATED( + 2.1, + "Serialize DataSet directly or use DataSetWithCellSetTypes for weird CellSets.") + SerializableDataSet : DataSetWithCellSetTypes +{ + using DataSetWithCellSetTypes::DataSetWithCellSetTypes; +}; + } } // vtkm::cont namespace mangled_diy_namespace { -template -struct Serialization> +template <> +struct VTKM_CONT_EXPORT Serialization +{ + static VTKM_CONT void foo(); + static VTKM_CONT void save(BinaryBuffer& bb, const vtkm::cont::DataSet& obj); + static VTKM_CONT void load(BinaryBuffer& bb, vtkm::cont::DataSet& obj); +}; + +template +struct Serialization> { private: - using Type = vtkm::cont::SerializableDataSet; + using Type = vtkm::cont::DataSetWithCellSetTypes; public: static VTKM_CONT void save(BinaryBuffer& bb, const Type& serializable) { const auto& dataset = serializable.DataSet; - vtkmdiy::save(bb, dataset.GetCellSet().ResetCellSetList(CellSetTypesList{})); + vtkmdiy::save(bb, dataset.GetCellSet().ResetCellSetList(vtkm::List{})); vtkm::IdComponent numberOfFields = dataset.GetNumberOfFields(); vtkmdiy::save(bb, numberOfFields); @@ -472,7 +505,7 @@ public: auto& dataset = serializable.DataSet; dataset = {}; // clear - vtkm::cont::UncertainCellSet cells; + vtkm::cont::UncertainCellSet> cells; vtkmdiy::load(bb, cells); dataset.SetCellSet(cells); @@ -496,6 +529,20 @@ public: } }; +template +struct Serialization>> + : Serialization> +{ +}; + +VTKM_DEPRECATED_SUPPRESS_BEGIN +template +struct Serialization> + : Serialization> +{ +}; +VTKM_DEPRECATED_SUPPRESS_END + } // diy /// @endcond SERIALIZATION diff --git a/vtkm/cont/testing/UnitTestSerializationDataSet.cxx b/vtkm/cont/testing/UnitTestSerializationDataSet.cxx index 4299688d6..0c8af712d 100644 --- a/vtkm/cont/testing/UnitTestSerializationDataSet.cxx +++ b/vtkm/cont/testing/UnitTestSerializationDataSet.cxx @@ -22,16 +22,26 @@ using CellSetTypes = vtkm::List, vtkm::cont::CellSetStructured<2>, vtkm::cont::CellSetStructured<3>>; -using DataSetWrapper = vtkm::cont::SerializableDataSet; +using DataSetWrapper = vtkm::cont::DataSetWithCellSetTypes; -VTKM_CONT void TestEqualDataSet(const DataSetWrapper& ds1, const DataSetWrapper& ds2) +VTKM_CONT void TestEqualDataSetWrapper(const DataSetWrapper& ds1, const DataSetWrapper& ds2) { VTKM_TEST_ASSERT(test_equal_DataSets(ds1.DataSet, ds2.DataSet, CellSetTypes{})); } +VTKM_CONT void TestEqualDataSet(const vtkm::cont::DataSet& ds1, const vtkm::cont::DataSet& ds2) +{ + VTKM_TEST_ASSERT(test_equal_DataSets(ds1, ds2, CellSetTypes{})); +} + void RunTest(const vtkm::cont::DataSet& ds) { - TestSerialization(DataSetWrapper(ds), TestEqualDataSet); + VTKM_DEPRECATED_SUPPRESS_BEGIN + TestSerialization(vtkm::cont::SerializableDataSet(ds), + TestEqualDataSetWrapper); + VTKM_DEPRECATED_SUPPRESS_END + TestSerialization(DataSetWrapper(ds), TestEqualDataSetWrapper); + TestSerialization(ds, TestEqualDataSet); } void TestDataSetSerialization() diff --git a/vtkm/filter/scalar_topology/testing/TestingContourTreeUniformDistributedFilter.h b/vtkm/filter/scalar_topology/testing/TestingContourTreeUniformDistributedFilter.h index c511aafb0..a43db23a3 100644 --- a/vtkm/filter/scalar_topology/testing/TestingContourTreeUniformDistributedFilter.h +++ b/vtkm/filter/scalar_topology/testing/TestingContourTreeUniformDistributedFilter.h @@ -314,9 +314,6 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed( { // Mutiple ranks -> Some assembly required. Collect data // on rank 0, all other ranks return empty data sets - using FieldTypeList = vtkm::ListAppend>; - using DataSetWrapper = - vtkm::cont::SerializableDataSet; // Communicate results to rank 0 auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); @@ -331,8 +328,7 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed( p.enqueue(root, result.GetNumberOfPartitions()); for (const vtkm::cont::DataSet& curr_ds : result) { - auto curr_sds = DataSetWrapper(curr_ds); - p.enqueue(root, curr_sds); + p.enqueue(root, curr_ds); } }); // Exchange data, i.e., send to rank 0 (pass "true" to exchange data between @@ -352,9 +348,9 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed( for (vtkm::Id currReceiveDataSetNo = 0; currReceiveDataSetNo < numberOfDataSetsToReceive; ++currReceiveDataSetNo) { - vtkm::cont::SerializableDataSet<> sds; - p.dequeue({ receiveFromRank, receiveFromRank }, sds); - combined_result.AppendPartition(sds.DataSet); + vtkm::cont::DataSet dsIncoming; + p.dequeue({ receiveFromRank, receiveFromRank }, dsIncoming); + combined_result.AppendPartition(dsIncoming); } } }); From 85bbcb9326e4ebec43defd3aeda9739e89a1ab36 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 2 Mar 2023 17:41:20 -0500 Subject: [PATCH 36/64] ascent,ci,olcf: split build and test stage --- .gitlab/ci/ascent.yml | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/.gitlab/ci/ascent.yml b/.gitlab/ci/ascent.yml index 0ba546b21..a9d2111f1 100644 --- a/.gitlab/ci/ascent.yml +++ b/.gitlab/ci/ascent.yml @@ -34,10 +34,14 @@ build:ascent_gcc_cuda: stage: build - tags: [olcf, ascent, nobatch] + tags: [olcf, ascent, batch] extends: - .ascent_gcc_cuda - .run_ascent_ci + - .cmake_build_artifacts + variables: + SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 + timeout: 125 minutes before_script: - *setup_env_ecpci - ccache -z @@ -48,12 +52,11 @@ build:ascent_gcc_cuda: script: - CTEST_MAX_PARALLELISM=8 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake - ctest -VV -S .gitlab/ci/ctest_configure.cmake - artifacts: - expire_in: 24 hours - when: always - paths: - - build/ - timeout: 10 minutes + - GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c42 ctest -VV -S .gitlab/ci/ctest_build.cmake + after_script: + - *setup_env_ecpci + - ccache -s + - ctest -VV -S .gitlab/ci/ctest_submit_build.cmake test:ascent_gcc_cuda: stage: test @@ -67,17 +70,16 @@ test:ascent_gcc_cuda: dependencies: - build:ascent_gcc_cuda variables: - SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 -alloc_flags gpudefault + CTEST_MAX_PARALLELISM: 4 # We need this to skip ctest_submit from being run inside a jsrun job GITLAB_CI_EMULATION: 1 + SCHEDULER_PARAMETERS: -P CSC331 -W 1:00 -nnodes 1 -alloc_flags gpudefault + timeout: 65 minutes before_script: - *setup_env_ecpci script: - - jsrun -n1 -a1 -g1 -c42 ctest -VV -S .gitlab/ci/ctest_build.cmake - - CTEST_MAX_PARALLELISM=4 jsrun -n1 -a1 -g1 -c8 ctest -VV -S .gitlab/ci/ctest_test.cmake + - cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake + - jsrun -n1 -a1 -g1 -c8 ctest -VV -S .gitlab/ci/ctest_test.cmake after_script: - *setup_env_ecpci - - ccache -s - - ctest -VV -S .gitlab/ci/ctest_submit_build.cmake - ctest -VV -S .gitlab/ci/ctest_submit_test.cmake - timeout: 120 minutes From 11b56f66d0a6054210bf7dca6afe6c11346ac39d Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Fri, 3 Mar 2023 11:39:18 -0500 Subject: [PATCH 37/64] ascent,ci,olcf: increase build parallel level --- .gitlab/ci/ascent.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/ascent.yml b/.gitlab/ci/ascent.yml index a9d2111f1..e348236c2 100644 --- a/.gitlab/ci/ascent.yml +++ b/.gitlab/ci/ascent.yml @@ -50,7 +50,7 @@ build:ascent_gcc_cuda: - git-lfs install - git-lfs pull lfs script: - - CTEST_MAX_PARALLELISM=8 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake + - CTEST_MAX_PARALLELISM=32 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake - ctest -VV -S .gitlab/ci/ctest_configure.cmake - GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c42 ctest -VV -S .gitlab/ci/ctest_build.cmake after_script: From 3579deb9de409f9ceba09c3adfceaaf9d3d7e71e Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 2 Mar 2023 18:57:12 -0500 Subject: [PATCH 38/64] ascent,ci,olcf: move build to scratch dir --- .gitlab/ci/ascent.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/ascent.yml b/.gitlab/ci/ascent.yml index e348236c2..3b11d59e5 100644 --- a/.gitlab/ci/ascent.yml +++ b/.gitlab/ci/ascent.yml @@ -2,7 +2,7 @@ .ascent_gcc_cuda: variables: CCACHE_BASEDIR: "/gpfs/wolf/" - CCACHE_DIR: "/gpfs/wolf/proj-shared/csc331/vtk-m/ci/ccache/" + CCACHE_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/ccache" # -isystem= is not affected by CCACHE_BASEDIR, thus we must ignore it CCACHE_IGNOREOPTIONS: "-isystem=*" CCACHE_NOHASHDIR: "true" @@ -12,7 +12,7 @@ CMAKE_BUILD_TYPE: "RelWithDebInfo" CMAKE_GENERATOR: "Ninja" CUDAHOSTCXX: "g++" - CUSTOM_CI_BUILDS_DIR: "/gpfs/wolf/proj-shared/csc331/vtk-m/ci/runtime" + CUSTOM_CI_BUILDS_DIR: "/gpfs/wolf/csc331/scratch/vbolea/ci/vtk-m" VTKM_SETTINGS: cuda+ascent+ccache JOB_MODULES: >- @@ -30,7 +30,7 @@ module purge module load ${JOB_MODULES} module list - export PATH="/gpfs/wolf/proj-shared/csc331/vtk-m/ci/utils:$PATH" + export PATH="/gpfs/wolf/csc331/scratch/vbolea/ci/utils:$PATH" build:ascent_gcc_cuda: stage: build From 8033338ce125693cbcb542fb0dfdf6bb1c9af229 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Fri, 3 Mar 2023 18:32:57 -0500 Subject: [PATCH 39/64] ascent,ci,olcf: tune ascent build parallel parameters --- .gitlab/ci/ascent.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/ascent.yml b/.gitlab/ci/ascent.yml index 3b11d59e5..19e33cf7e 100644 --- a/.gitlab/ci/ascent.yml +++ b/.gitlab/ci/ascent.yml @@ -40,7 +40,7 @@ build:ascent_gcc_cuda: - .run_ascent_ci - .cmake_build_artifacts variables: - SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 + SCHEDULER_PARAMETERS: -P CSC331 -W 2:00 -nnodes 1 -alloc_flags smt1 timeout: 125 minutes before_script: - *setup_env_ecpci @@ -50,9 +50,12 @@ build:ascent_gcc_cuda: - git-lfs install - git-lfs pull lfs script: - - CTEST_MAX_PARALLELISM=32 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake + # Each Ascent (Summit) node has 172 threads (43 cores). SMT1 is needed to + # avoid L1 cache pollution among different processes. Thus, using 40 cores + # seems a reasonable choice which leaves a couple of cores for system processes. + - CTEST_MAX_PARALLELISM=40 cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake - ctest -VV -S .gitlab/ci/ctest_configure.cmake - - GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c42 ctest -VV -S .gitlab/ci/ctest_build.cmake + - GITLAB_CI_EMULATION=1 jsrun -n1 -a1 -g1 -c40 -bpacked:40 ctest -VV -S .gitlab/ci/ctest_build.cmake after_script: - *setup_env_ecpci - ccache -s @@ -70,6 +73,8 @@ test:ascent_gcc_cuda: dependencies: - build:ascent_gcc_cuda variables: + # For tests we want to use a small number of proccesses, for some reason + # a higher parallelism number tend to results in test malfunctions. CTEST_MAX_PARALLELISM: 4 # We need this to skip ctest_submit from being run inside a jsrun job GITLAB_CI_EMULATION: 1 @@ -79,7 +84,7 @@ test:ascent_gcc_cuda: - *setup_env_ecpci script: - cmake -V -P .gitlab/ci/config/gitlab_ci_setup.cmake - - jsrun -n1 -a1 -g1 -c8 ctest -VV -S .gitlab/ci/ctest_test.cmake + - jsrun -n1 -a1 -g1 -c1 ctest -VV -S .gitlab/ci/ctest_test.cmake after_script: - *setup_env_ecpci - ctest -VV -S .gitlab/ci/ctest_submit_test.cmake From 4b19139f3d4573c2861756b7782457906ae08f6b Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 6 Mar 2023 08:48:50 -0700 Subject: [PATCH 40/64] Add tests to UnitTestArrayRangeCompute Make the test a bit more complete by testing more array types. --- .../testing/UnitTestArrayRangeCompute.cxx | 97 +++++++++++++------ 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx b/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx index 1842e0d5e..a5a2e245c 100644 --- a/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx +++ b/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx @@ -11,17 +11,22 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include +#include #include @@ -31,12 +36,12 @@ namespace constexpr vtkm::Id ARRAY_SIZE = 20; template -void CheckRange(const vtkm::cont::ArrayHandle& array, bool checkUnknown = true) +void VerifyRange(const vtkm::cont::ArrayHandle& array, + const vtkm::cont::ArrayHandle& computedRangeArray) { using Traits = vtkm::VecTraits; vtkm::IdComponent numComponents = Traits::NUM_COMPONENTS; - vtkm::cont::ArrayHandle computedRangeArray = vtkm::cont::ArrayRangeCompute(array); VTKM_TEST_ASSERT(computedRangeArray.GetNumberOfValues() == numComponents); auto computedRangePortal = computedRangeArray.ReadPortal(); @@ -54,28 +59,13 @@ void CheckRange(const vtkm::cont::ArrayHandle& array, bool checkUnknown = VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max)); VTKM_TEST_ASSERT(test_equal(expectedRange, computedRange)); } +} - if (checkUnknown) - { - computedRangeArray = vtkm::cont::ArrayRangeCompute(vtkm::cont::UnknownArrayHandle{ array }); - VTKM_TEST_ASSERT(computedRangeArray.GetNumberOfValues() == numComponents); - computedRangePortal = computedRangeArray.ReadPortal(); - - portal = array.ReadPortal(); - for (vtkm::IdComponent component = 0; component < numComponents; ++component) - { - vtkm::Range computedRange = computedRangePortal.Get(component); - vtkm::Range expectedRange; - for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index) - { - T value = portal.Get(index); - expectedRange.Include(Traits::GetComponent(value, component)); - } - VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Min)); - VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max)); - VTKM_TEST_ASSERT(test_equal(expectedRange, computedRange)); - } - } +template +void CheckRange(const vtkm::cont::ArrayHandle& array) +{ + VerifyRange(array, vtkm::cont::ArrayRangeCompute(array)); + VerifyRange(array, vtkm::cont::ArrayRangeCompute(vtkm::cont::UnknownArrayHandle{ array })); } template @@ -119,7 +109,7 @@ void TestSOAArray(vtkm::TypeTraitsScalarTag) } template -void TestStrideArray(vtkm::TypeTraitsScalarTag) +void TestStrideArray() { std::cout << "Checking stride array" << std::endl; vtkm::cont::ArrayHandleBasic array; @@ -127,6 +117,16 @@ void TestStrideArray(vtkm::TypeTraitsScalarTag) CheckRange(vtkm::cont::ArrayHandleStride(array, ARRAY_SIZE / 2, 2, 1)); } +template +void TestCastArray() +{ + std::cout << "Checking cast array" << std::endl; + using CastType = typename vtkm::VecTraits::template ReplaceBaseComponentType; + vtkm::cont::ArrayHandle array; + FillArray(array); + CheckRange(vtkm::cont::make_ArrayHandleCast(array)); +} + template void TestCartesianProduct(vtkm::TypeTraitsScalarTag) { @@ -151,7 +151,7 @@ void TestCartesianProduct(vtkm::TypeTraitsVectorTag) template void TestComposite(vtkm::TypeTraitsScalarTag) { - std::cout << "Checking composite vector" << std::endl; + std::cout << "Checking composite vector array" << std::endl; vtkm::cont::ArrayHandleBasic array0; FillArray(array0); @@ -169,6 +169,32 @@ void TestComposite(vtkm::TypeTraitsVectorTag) // Skip test. } +template +void TestGroup(vtkm::TypeTraitsScalarTag) +{ + std::cout << "Checking group vec array" << std::endl; + + vtkm::cont::ArrayHandleBasic array; + FillArray(array); + CheckRange(vtkm::cont::make_ArrayHandleGroupVec<2>(array)); +} + +template +void TestGroup(vtkm::TypeTraitsVectorTag) +{ + // Skip test. +} + +template +void TestView() +{ + std::cout << "Checking view array" << std::endl; + + vtkm::cont::ArrayHandleBasic array; + FillArray(array); + CheckRange(vtkm::cont::make_ArrayHandleView(array, 2, ARRAY_SIZE - 5)); +} + template void TestConstant() { @@ -205,15 +231,29 @@ void TestUniformPointCoords() vtkm::cont::ArrayHandleUniformPointCoordinates(vtkm::Id3(ARRAY_SIZE, ARRAY_SIZE, ARRAY_SIZE))); } +void TestXGCCoordinates() +{ + std::cout << "Checking XGC coordinates array" << std::endl; + vtkm::cont::ArrayHandle array; + FillArray(array); + CheckRange(vtkm::cont::make_ArrayHandleXGCCoordinates(array, 4, true)); +} + struct DoTestFunctor { template void operator()(T) const { + typename vtkm::TypeTraits::DimensionalityTag dimensionality{}; + TestBasicArray(); - TestSOAArray(typename vtkm::TypeTraits::DimensionalityTag{}); - TestCartesianProduct(typename vtkm::TypeTraits::DimensionalityTag{}); - TestComposite(typename vtkm::TypeTraits::DimensionalityTag{}); + TestSOAArray(dimensionality); + TestStrideArray(); + TestCastArray(); + TestCartesianProduct(dimensionality); + TestComposite(dimensionality); + TestGroup(dimensionality); + TestView(); TestConstant(); TestCounting(typename std::is_signed::ComponentType>::type{}); } @@ -226,6 +266,7 @@ void DoTest() std::cout << "*** Specific arrays *****************" << std::endl; TestIndex(); TestUniformPointCoords(); + TestXGCCoordinates(); } } // anonymous namespace From 58fc99c2f87d9c184ce86d08cc9b8b97eafcd73f Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 6 Mar 2023 12:35:38 -0700 Subject: [PATCH 41/64] Fix fast paths for ArrayRangeCompute The precompiled `ArrayRangeCompute` function was not following proper fast paths for special arrays. For example, when computing the range of an `ArrayHandleUniformPointCoordinates`, the ranges should be taken from the origin and spacing of the special array. However, the precompiled version was calling the generic range computation, which was doing an unnecessary reduction over the entire array. These fast paths have been fixed. These mistakes in the code were caused by quirks in how templated method overloading works. To prevent this mistake from happening again in the precompiled `ArrayRangeCompute` function and elsewhere, all templated forms of `ArrayRangeCompute` have been deprecated. Most will call `ArrayRangeCompute` with no issues. For those that need the templated version, `ArrayRangeComputeTemplate` replaces the old templated `ArrayRangeCompute`. There is exactly one templated declaration of `ArrayRangeComputeTemplate` that uses a class, `ArrayRangeComputeImpl`, with partial specialization to ensure the correct form is used. --- docs/changelog/array-range-fast-paths.md | 18 ++ vtkm/cont/ArrayHandleCartesianProduct.h | 73 +++++++ vtkm/cont/ArrayHandleConstant.h | 33 ++++ vtkm/cont/ArrayHandleCounting.h | 47 +++++ vtkm/cont/ArrayHandleIndex.h | 24 +++ .../ArrayHandleUniformPointCoordinates.cxx | 22 +++ .../cont/ArrayHandleUniformPointCoordinates.h | 12 ++ vtkm/cont/ArrayRangeCompute.cxx | 145 +++----------- vtkm/cont/ArrayRangeCompute.h | 179 ++---------------- vtkm/cont/ArrayRangeComputeTemplate.h | 37 +++- .../testing/UnitTestArrayRangeCompute.cxx | 1 - .../meshtypes/ContourTreeMesh.h | 3 +- .../worklet/OrientCellNormals.h | 1 - 13 files changed, 305 insertions(+), 290 deletions(-) create mode 100644 docs/changelog/array-range-fast-paths.md diff --git a/docs/changelog/array-range-fast-paths.md b/docs/changelog/array-range-fast-paths.md new file mode 100644 index 000000000..7c2c47eae --- /dev/null +++ b/docs/changelog/array-range-fast-paths.md @@ -0,0 +1,18 @@ +# Fast paths for `ArrayRangeCompute` fixed + +The precompiled `ArrayRangeCompute` function was not following proper fast +paths for special arrays. For example, when computing the range of an +`ArrayHandleUniformPointCoordinates`, the ranges should be taken from the +origin and spacing of the special array. However, the precompiled version +was calling the generic range computation, which was doing an unnecessary +reduction over the entire array. These fast paths have been fixed. + +These mistakes in the code were caused by quirks in how templated method +overloading works. To prevent this mistake from happening again in the +precompiled `ArrayRangeCompute` function and elsewhere, all templated forms +of `ArrayRangeCompute` have been deprecated. Most will call +`ArrayRangeCompute` with no issues. For those that need the templated +version, `ArrayRangeComputeTemplate` replaces the old templated +`ArrayRangeCompute`. There is exactly one templated declaration of +`ArrayRangeComputeTemplate` that uses a class, `ArrayRangeComputeImpl`, +with partial specialization to ensure the correct form is used. diff --git a/vtkm/cont/ArrayHandleCartesianProduct.h b/vtkm/cont/ArrayHandleCartesianProduct.h index 649f770ea..037f9ee03 100644 --- a/vtkm/cont/ArrayHandleCartesianProduct.h +++ b/vtkm/cont/ArrayHandleCartesianProduct.h @@ -11,6 +11,8 @@ #define vtk_m_cont_ArrayHandleCartesianProduct_h #include +#include +#include #include #include @@ -486,6 +488,77 @@ struct ArrayExtractComponentImpl> } }; +template +struct ArrayRangeComputeImpl; + +template +struct VTKM_CONT_EXPORT ArrayRangeComputeImpl> +{ + template + VTKM_CONT vtkm::cont::ArrayHandle operator()( + const vtkm::cont::ArrayHandle, + vtkm::cont::StorageTagCartesianProduct>& input_, + vtkm::cont::DeviceAdapterId device) const + { + vtkm::cont::ArrayHandle result; + result.Allocate(3); + auto resultPortal = result.WritePortal(); + + const vtkm::cont::ArrayHandleCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>& input = input_; + vtkm::cont::ArrayHandle componentRangeArray; + + vtkm::IdComponent index = 0; + vtkm::cont::ArrayHandle firstArray = input.GetFirstArray(); + componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl{}(firstArray, device); + vtkm::Id numSubComponents = componentRangeArray.GetNumberOfValues(); + if (numSubComponents > 1) + { + result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On); + resultPortal = result.WritePortal(); + } + auto componentRangePortal = componentRangeArray.ReadPortal(); + for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent) + { + resultPortal.Set(index, componentRangePortal.Get(subComponent)); + ++index; + } + + vtkm::cont::ArrayHandle secondArray = input.GetSecondArray(); + componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl{}(secondArray, device); + numSubComponents = componentRangeArray.GetNumberOfValues(); + if (numSubComponents > 1) + { + result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On); + resultPortal = result.WritePortal(); + } + componentRangePortal = componentRangeArray.ReadPortal(); + for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent) + { + resultPortal.Set(index, componentRangePortal.Get(subComponent)); + ++index; + } + + vtkm::cont::ArrayHandle thirdArray = input.GetThirdArray(); + componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl{}(thirdArray, device); + numSubComponents = componentRangeArray.GetNumberOfValues(); + if (numSubComponents > 1) + { + result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On); + resultPortal = result.WritePortal(); + } + componentRangePortal = componentRangeArray.ReadPortal(); + for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent) + { + resultPortal.Set(index, componentRangePortal.Get(subComponent)); + ++index; + } + + return result; + } +}; + } // namespace internal } diff --git a/vtkm/cont/ArrayHandleConstant.h b/vtkm/cont/ArrayHandleConstant.h index 106f4354e..45d67e198 100644 --- a/vtkm/cont/ArrayHandleConstant.h +++ b/vtkm/cont/ArrayHandleConstant.h @@ -12,6 +12,9 @@ #include +#include +#include + namespace vtkm { namespace cont @@ -90,6 +93,36 @@ vtkm::cont::ArrayHandleConstant make_ArrayHandleConstant(T value, vtkm::Id nu { return vtkm::cont::ArrayHandleConstant(value, numberOfValues); } + +namespace internal +{ + +template +struct ArrayRangeComputeImpl; + +template <> +struct VTKM_CONT_EXPORT ArrayRangeComputeImpl +{ + template + VTKM_CONT vtkm::cont::ArrayHandle operator()( + const vtkm::cont::ArrayHandle& input, + vtkm::cont::DeviceAdapterId) const + { + auto value = vtkm::make_VecFlat(input.ReadPortal().Get(0)); + + vtkm::cont::ArrayHandle result; + result.Allocate(value.GetNumberOfComponents()); + auto resultPortal = result.WritePortal(); + for (vtkm::IdComponent index = 0; index < value.GetNumberOfComponents(); ++index) + { + resultPortal.Set(index, vtkm::Range{ value[index], value[index] }); + } + return result; + } +}; + +} // namespace internal + } } // vtkm::cont diff --git a/vtkm/cont/ArrayHandleCounting.h b/vtkm/cont/ArrayHandleCounting.h index 7f6f08e0d..2840eeaeb 100644 --- a/vtkm/cont/ArrayHandleCounting.h +++ b/vtkm/cont/ArrayHandleCounting.h @@ -12,6 +12,7 @@ #include +#include #include #include @@ -152,6 +153,52 @@ make_ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm:: { return vtkm::cont::ArrayHandleCounting(start, step, length); } + +namespace internal +{ + +template +struct ArrayRangeComputeImpl; + +template <> +struct VTKM_CONT_EXPORT ArrayRangeComputeImpl +{ + template + VTKM_CONT vtkm::cont::ArrayHandle operator()( + const vtkm::cont::ArrayHandle& input, + vtkm::cont::DeviceAdapterId) const + { + using Traits = vtkm::VecTraits; + vtkm::cont::ArrayHandle result; + result.Allocate(Traits::NUM_COMPONENTS); + auto portal = result.WritePortal(); + if (portal.GetNumberOfValues() > 0) + { + T first = input.ReadPortal().Get(0); + T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1); + for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex) + { + auto firstComponent = Traits::GetComponent(first, cIndex); + auto lastComponent = Traits::GetComponent(last, cIndex); + portal.Set(cIndex, + vtkm::Range(vtkm::Min(firstComponent, lastComponent), + vtkm::Max(firstComponent, lastComponent))); + } + } + else + { + // Array is empty + for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex) + { + portal.Set(cIndex, vtkm::Range{}); + } + } + return result; + } +}; + +} // namespace internal + } } // namespace vtkm::cont diff --git a/vtkm/cont/ArrayHandleIndex.h b/vtkm/cont/ArrayHandleIndex.h index d5dcc0fc9..7bccba25b 100644 --- a/vtkm/cont/ArrayHandleIndex.h +++ b/vtkm/cont/ArrayHandleIndex.h @@ -10,6 +10,7 @@ #ifndef vtk_m_cont_ArrayHandleIndex_h #define vtk_m_cont_ArrayHandleIndex_h +#include #include namespace vtkm @@ -71,6 +72,29 @@ VTKM_CONT inline vtkm::cont::ArrayHandleIndex make_ArrayHandleIndex(vtkm::Id len { return vtkm::cont::ArrayHandleIndex(length); } + +namespace internal +{ + +template +struct ArrayRangeComputeImpl; + +template <> +struct VTKM_CONT_EXPORT ArrayRangeComputeImpl +{ + VTKM_CONT vtkm::cont::ArrayHandle operator()( + const vtkm::cont::ArrayHandle& input, + vtkm::cont::DeviceAdapterId) const + { + vtkm::cont::ArrayHandle result; + result.Allocate(1); + result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1)); + return result; + } +}; + +} // namespace internal + } } // namespace vtkm::cont diff --git a/vtkm/cont/ArrayHandleUniformPointCoordinates.cxx b/vtkm/cont/ArrayHandleUniformPointCoordinates.cxx index d12e79b6a..a4b5f5668 100644 --- a/vtkm/cont/ArrayHandleUniformPointCoordinates.cxx +++ b/vtkm/cont/ArrayHandleUniformPointCoordinates.cxx @@ -86,6 +86,28 @@ ArrayExtractComponentImpl::operator()( } } +VTKM_CONT vtkm::cont::ArrayHandle +ArrayRangeComputeImpl::operator()( + const vtkm::cont::ArrayHandleUniformPointCoordinates& input, + vtkm::cont::DeviceAdapterId vtkmNotUsed(device)) const +{ + vtkm::internal::ArrayPortalUniformPointCoordinates portal = input.ReadPortal(); + + // In this portal we know that the min value is the first entry and the + // max value is the last entry. + vtkm::Vec3f minimum = portal.Get(0); + vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1); + + vtkm::cont::ArrayHandle rangeArray; + rangeArray.Allocate(3); + vtkm::cont::ArrayHandle::WritePortalType outPortal = rangeArray.WritePortal(); + outPortal.Set(0, vtkm::Range(minimum[0], maximum[0])); + outPortal.Set(1, vtkm::Range(minimum[1], maximum[1])); + outPortal.Set(2, vtkm::Range(minimum[2], maximum[2])); + + return rangeArray; +} + } // namespace internal } diff --git a/vtkm/cont/ArrayHandleUniformPointCoordinates.h b/vtkm/cont/ArrayHandleUniformPointCoordinates.h index ebbf18975..a0f425d27 100644 --- a/vtkm/cont/ArrayHandleUniformPointCoordinates.h +++ b/vtkm/cont/ArrayHandleUniformPointCoordinates.h @@ -10,6 +10,7 @@ #ifndef vtk_m_cont_ArrayHandleUniformPointCoordinates_h #define vtk_m_cont_ArrayHandleUniformPointCoordinates_h +#include #include #include #include @@ -83,6 +84,17 @@ struct VTKM_CONT_EXPORT ArrayExtractComponentImpl +struct ArrayRangeComputeImpl; + +template <> +struct VTKM_CONT_EXPORT ArrayRangeComputeImpl +{ + VTKM_CONT vtkm::cont::ArrayHandle operator()( + const vtkm::cont::ArrayHandleUniformPointCoordinates& input, + vtkm::cont::DeviceAdapterId device) const; +}; + } // namespace internal } diff --git a/vtkm/cont/ArrayRangeCompute.cxx b/vtkm/cont/ArrayRangeCompute.cxx index 8ff99fdd2..f2e1a0f31 100644 --- a/vtkm/cont/ArrayRangeCompute.cxx +++ b/vtkm/cont/ArrayRangeCompute.cxx @@ -12,118 +12,16 @@ #include -namespace vtkm -{ -namespace cont -{ - -void ThrowArrayRangeComputeFailed() -{ - throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device."); -} - -#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(T, Storage) \ - VTKM_CONT \ - vtkm::cont::ArrayHandle ArrayRangeCompute( \ - const vtkm::cont::ArrayHandle& input, vtkm::cont::DeviceAdapterId device) \ - { \ - return detail::ArrayRangeComputeImpl(input, device); \ - } \ - struct SwallowSemicolon -#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(T, N, Storage) \ - VTKM_CONT \ - vtkm::cont::ArrayHandle ArrayRangeCompute( \ - const vtkm::cont::ArrayHandle, Storage>& input, \ - vtkm::cont::DeviceAdapterId device) \ - { \ - return detail::ArrayRangeComputeImpl(input, device); \ - } \ - struct SwallowSemicolon - -#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(Storage) \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int8, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt8, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int16, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt16, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int32, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt32, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int64, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt64, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float32, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float64, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(char, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(signed VTKM_UNUSED_INT_TYPE, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(unsigned VTKM_UNUSED_INT_TYPE, Storage) - -#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(N, Storage) \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int8, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt8, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int16, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt16, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int32, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt32, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int64, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt64, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(char, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \ - VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage) - -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagBasic); - -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic); -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic); -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic); - -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA); -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA); -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA); - -VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagStride); - -VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates); -VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates); - -#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T -#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC -#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T -#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC - -// Special implementation for regular point coordinates, which are easy -// to determine. -VTKM_CONT -vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& array, - vtkm::cont::DeviceAdapterId) -{ - vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.ReadPortal(); - - // In this portal we know that the min value is the first entry and the - // max value is the last entry. - vtkm::Vec3f minimum = portal.Get(0); - vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1); - - vtkm::cont::ArrayHandle rangeArray; - rangeArray.Allocate(3); - vtkm::cont::ArrayHandle::WritePortalType outPortal = rangeArray.WritePortal(); - outPortal.Set(0, vtkm::Range(minimum[0], maximum[0])); - outPortal.Set(1, vtkm::Range(minimum[1], maximum[1])); - outPortal.Set(2, vtkm::Range(minimum[2], maximum[2])); - - return rangeArray; -} - -vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& input, - vtkm::cont::DeviceAdapterId) -{ - vtkm::cont::ArrayHandle result; - result.Allocate(1); - result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1)); - return result; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace { @@ -152,7 +50,7 @@ struct ComputeRangeFunctor vtkm::cont::DeviceAdapterId device, vtkm::cont::ArrayHandle& ranges) const { - ranges = vtkm::cont::ArrayRangeCompute(array, device); + ranges = vtkm::cont::ArrayRangeComputeTemplate(array, device); } // Used with vtkm::ListForEach to get components @@ -172,7 +70,7 @@ struct ComputeRangeFunctor { vtkm::cont::ArrayHandleStride componentArray = array.ExtractComponent(componentI); vtkm::cont::ArrayHandle componentRange = - vtkm::cont::ArrayRangeCompute(componentArray, device); + vtkm::cont::ArrayRangeComputeTemplate(componentArray, device); rangePortal.Set(componentI, componentRange.ReadPortal().Get(0)); } success = true; @@ -191,6 +89,21 @@ vtkm::cont::ArrayHandle ComputeForStorage(const vtkm::cont::Unknown } // anonymous namespace +namespace vtkm +{ +namespace cont +{ + +namespace internal +{ + +void ThrowArrayRangeComputeFailed() +{ + throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device."); +} + +} // namespace internal + vtkm::cont::ArrayHandle ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle& array, vtkm::cont::DeviceAdapterId device) { @@ -214,7 +127,7 @@ vtkm::cont::ArrayHandle ArrayRangeCompute(const vtkm::cont::Unknown { vtkm::cont::ArrayHandleUniformPointCoordinates uniformPoints; array.AsArrayHandle(uniformPoints); - return vtkm::cont::ArrayRangeCompute(uniformPoints, device); + return vtkm::cont::ArrayRangeComputeTemplate(uniformPoints, device); } using CartesianProductStorage = vtkm::cont::StorageTagCartesianProduct ArrayRangeCompute(const vtkm::cont::Unknown } if (array.IsStorageType()) { - return ArrayRangeCompute(array.AsArrayHandle(), device); + return ArrayRangeComputeTemplate(array.AsArrayHandle(), device); } } catch (vtkm::cont::ErrorBadType&) diff --git a/vtkm/cont/ArrayRangeCompute.h b/vtkm/cont/ArrayRangeCompute.h index dfbc01f80..e87b612ea 100644 --- a/vtkm/cont/ArrayRangeCompute.h +++ b/vtkm/cont/ArrayRangeCompute.h @@ -31,7 +31,6 @@ namespace vtkm namespace cont { -///@{ /// \brief Compute the range of the data in an array handle. /// /// Given an `ArrayHandle`, this function computes the range (min and max) of @@ -48,179 +47,27 @@ namespace cont /// Note that the ArrayRangeCompute.h header file contains only precompiled overloads /// of ArrayRangeCompute. This is so that ArrayRangeCompute.h can be included in /// code that does not use a device compiler. If you need to compute array ranges -/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to include -/// ArrayRangeComputeTemplate.h. This contains a templated version of ArrayRangeCompute -/// that will compile for any `ArrayHandle` type not already handled. +/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to use +/// `ArrayRangeComputeTemplate` (declared in `ArrayRangeComputeTemplate`), which +/// will compile for any `ArrayHandle` type not already handled. /// - VTKM_CONT_EXPORT vtkm::cont::ArrayHandle ArrayRangeCompute( const vtkm::cont::UnknownArrayHandle& array, vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{}); -#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(T, Storage) \ - VTKM_CONT_EXPORT \ - VTKM_CONT \ - vtkm::cont::ArrayHandle ArrayRangeCompute( \ - const vtkm::cont::ArrayHandle& input, \ - vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()) -#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(T, N, Storage) \ - VTKM_CONT_EXPORT \ - VTKM_CONT \ - vtkm::cont::ArrayHandle ArrayRangeCompute( \ - const vtkm::cont::ArrayHandle, Storage>& input, \ - vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()) - -#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(Storage) \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int8, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt8, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int16, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt16, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int32, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt32, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int64, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt64, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float32, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float64, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(char, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(signed VTKM_UNUSED_INT_TYPE, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(unsigned VTKM_UNUSED_INT_TYPE, Storage) - -#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(N, Storage) \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int8, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt8, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int16, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt16, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int32, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt32, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int64, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt64, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(char, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \ - VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage) - -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagBasic); - -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagBasic); -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagBasic); -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagBasic); - -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagSOA); -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagSOA); -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagSOA); - -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagStride); - -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates); -VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates); - -#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T -#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC -#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T -#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC - -VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& array, - vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()); - -// Implementation of cartesian products -template -VTKM_CONT inline vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle, - vtkm::cont::StorageTagCartesianProduct>& input_, - vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()) +namespace internal { - vtkm::cont::ArrayHandle result; - result.Allocate(3); - - vtkm::cont::ArrayHandle componentRangeArray; - vtkm::Range componentRange; - - vtkm::cont::ArrayHandleCartesianProduct, - vtkm::cont::ArrayHandle, - vtkm::cont::ArrayHandle> - input = input_; - vtkm::cont::ArrayHandle firstArray = input.GetFirstArray(); - componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, device); - componentRange = componentRangeArray.ReadPortal().Get(0); - result.WritePortal().Set(0, componentRange); - - vtkm::cont::ArrayHandle secondArray = input.GetSecondArray(); - componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, device); - componentRange = componentRangeArray.ReadPortal().Get(0); - result.WritePortal().Set(1, componentRange); - - vtkm::cont::ArrayHandle thirdArray = input.GetThirdArray(); - componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, device); - componentRange = componentRangeArray.ReadPortal().Get(0); - result.WritePortal().Set(2, componentRange); - - return result; -} - -// Implementation of constant arrays -template -VTKM_CONT inline vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& input, - vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{}) -{ - using Traits = vtkm::VecTraits; - const T value = vtkm::cont::ArrayHandleConstant(input).GetValue(); - vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value); - vtkm::cont::ArrayHandle result; - result.Allocate(numComponents); - auto portal = result.WritePortal(); - for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex) - { - auto component = Traits::GetComponent(value, cIndex); - portal.Set(cIndex, vtkm::Range(component, component)); - } - return result; -} - -// Implementation of counting arrays -template -VTKM_CONT inline vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& input, - vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{}) -{ - using Traits = vtkm::VecTraits; - vtkm::cont::ArrayHandle result; - result.Allocate(Traits::NUM_COMPONENTS); - auto portal = result.WritePortal(); - if (portal.GetNumberOfValues() > 0) - { - T first = input.ReadPortal().Get(0); - T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1); - for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex) - { - auto firstComponent = Traits::GetComponent(first, cIndex); - auto lastComponent = Traits::GetComponent(last, cIndex); - portal.Set(cIndex, - vtkm::Range(vtkm::Min(firstComponent, lastComponent), - vtkm::Max(firstComponent, lastComponent))); - } - } - else - { - // Array is empty - for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex) - { - portal.Set(cIndex, vtkm::Range{}); - } - } - return result; -} - -// Implementation of index arrays -VTKM_CONT_EXPORT vtkm::cont::ArrayHandle ArrayRangeCompute( - const vtkm::cont::ArrayHandle& input, - vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{}); -///@} VTKM_CONT_EXPORT void ThrowArrayRangeComputeFailed(); + +} // namespace internal + +VTKM_DEPRECATED(2.1, "Moved to vtkm::cont::internal.") +inline void ThrowArrayRangeComputeFailed() +{ + internal::ThrowArrayRangeComputeFailed(); +} + } } // namespace vtkm::cont diff --git a/vtkm/cont/ArrayRangeComputeTemplate.h b/vtkm/cont/ArrayRangeComputeTemplate.h index 2e593e1aa..aeab8c3c5 100644 --- a/vtkm/cont/ArrayRangeComputeTemplate.h +++ b/vtkm/cont/ArrayRangeComputeTemplate.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -42,8 +43,13 @@ struct ArrayRangeComputeFunctor } }; +} // namespace detail + +namespace internal +{ + template -inline vtkm::cont::ArrayHandle ArrayRangeComputeImpl( +inline vtkm::cont::ArrayHandle ArrayRangeComputeGeneric( const vtkm::cont::ArrayHandle& input, vtkm::cont::DeviceAdapterId device) { @@ -74,7 +80,7 @@ inline vtkm::cont::ArrayHandle ArrayRangeComputeImpl( initial[1] = T(std::numeric_limits::lowest()); const bool rangeComputed = vtkm::cont::TryExecuteOnDevice( - device, detail::ArrayRangeComputeFunctor{}, input, initial, result); + device, vtkm::cont::detail::ArrayRangeComputeFunctor{}, input, initial, result); if (!rangeComputed) { ThrowArrayRangeComputeFailed(); @@ -93,17 +99,38 @@ inline vtkm::cont::ArrayHandle ArrayRangeComputeImpl( return range; } -} // namespace detail +template +struct ArrayRangeComputeImpl +{ + template + vtkm::cont::ArrayHandle operator()(const vtkm::cont::ArrayHandle& input, + vtkm::cont::DeviceAdapterId device) const + { + return vtkm::cont::internal::ArrayRangeComputeGeneric(input, device); + } +}; + +} // namespace internal template -inline vtkm::cont::ArrayHandle ArrayRangeCompute( +inline vtkm::cont::ArrayHandle ArrayRangeComputeTemplate( const ArrayHandleType& input, vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{}) { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); - return detail::ArrayRangeComputeImpl(input, device); + return internal::ArrayRangeComputeImpl{}(input, device); } + +template +VTKM_DEPRECATED(2.1, "Use precompiled ArrayRangeCompute or ArrayRangeComputeTemplate.") +inline vtkm::cont::ArrayHandle ArrayRangeCompute( + const ArrayHandleType& input, + vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{}) +{ + return ArrayRangeComputeTemplate(input, device); +} + } } // namespace vtkm::cont diff --git a/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx b/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx index a5a2e245c..05f3b81f2 100644 --- a/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx +++ b/vtkm/cont/testing/UnitTestArrayRangeCompute.cxx @@ -65,7 +65,6 @@ template void CheckRange(const vtkm::cont::ArrayHandle& array) { VerifyRange(array, vtkm::cont::ArrayRangeCompute(array)); - VerifyRange(array, vtkm::cont::ArrayRangeCompute(vtkm::cont::UnknownArrayHandle{ array })); } template diff --git a/vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h b/vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h index 2971fb492..197f50f69 100644 --- a/vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h +++ b/vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h @@ -576,7 +576,8 @@ template inline void ContourTreeMesh::ComputeMaxNeighbors() { auto neighborCounts = make_ArrayHandleOffsetsToNumComponents(this->NeighborOffsets); - vtkm::cont::ArrayHandle rangeArray = vtkm::cont::ArrayRangeCompute(neighborCounts); + vtkm::cont::ArrayHandle rangeArray = + vtkm::cont::ArrayRangeComputeTemplate(neighborCounts); this->MaxNeighbors = static_cast(rangeArray.ReadPortal().Get(0).Max); } diff --git a/vtkm/filter/vector_analysis/worklet/OrientCellNormals.h b/vtkm/filter/vector_analysis/worklet/OrientCellNormals.h index eb1702392..c76ee9f07 100644 --- a/vtkm/filter/vector_analysis/worklet/OrientCellNormals.h +++ b/vtkm/filter/vector_analysis/worklet/OrientCellNormals.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include From 67d6780fba29b0070da16ea685895adc212ba6a9 Mon Sep 17 00:00:00 2001 From: Louis Gombert Date: Thu, 2 Mar 2023 22:34:59 +0100 Subject: [PATCH 42/64] Add Shrink filter This filter shrinks the cells of a DataSet towards their centroid, computed as the average position of the cell points --- docs/changelog/2.0/shrink-filter | 3 + .../filter/geometry_refinement/CMakeLists.txt | 2 + vtkm/filter/geometry_refinement/Shrink.cxx | 65 +++++++ vtkm/filter/geometry_refinement/Shrink.h | 48 +++++ .../testing/CMakeLists.txt | 1 + .../testing/UnitTestShrinkFilter.cxx | 169 ++++++++++++++++++ .../worklet/CMakeLists.txt | 1 + .../geometry_refinement/worklet/Shrink.h | 150 ++++++++++++++++ 8 files changed, 439 insertions(+) create mode 100644 docs/changelog/2.0/shrink-filter create mode 100644 vtkm/filter/geometry_refinement/Shrink.cxx create mode 100644 vtkm/filter/geometry_refinement/Shrink.h create mode 100644 vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx create mode 100644 vtkm/filter/geometry_refinement/worklet/Shrink.h diff --git a/docs/changelog/2.0/shrink-filter b/docs/changelog/2.0/shrink-filter new file mode 100644 index 000000000..36e523c31 --- /dev/null +++ b/docs/changelog/2.0/shrink-filter @@ -0,0 +1,3 @@ +# New Shrink filter + +The Shrink filter shrinks the cells of a DataSet towards their centroid, computed as the average position of the cell points. This filter disconnects the cells, duplicating the points connected to multiple cells. The resulting CellSet is always an `ExplicitCellSet`. diff --git a/vtkm/filter/geometry_refinement/CMakeLists.txt b/vtkm/filter/geometry_refinement/CMakeLists.txt index ff52259c9..b146ff5c3 100644 --- a/vtkm/filter/geometry_refinement/CMakeLists.txt +++ b/vtkm/filter/geometry_refinement/CMakeLists.txt @@ -8,6 +8,7 @@ ## PURPOSE. See the above copyright notice for more information. ##============================================================================ set(geometry_refinement_headers + Shrink.h SplitSharpEdges.h Tetrahedralize.h Triangulate.h @@ -16,6 +17,7 @@ set(geometry_refinement_headers ) set(geometry_refinement_sources + Shrink.cxx SplitSharpEdges.cxx Tetrahedralize.cxx Triangulate.cxx diff --git a/vtkm/filter/geometry_refinement/Shrink.cxx b/vtkm/filter/geometry_refinement/Shrink.cxx new file mode 100644 index 000000000..ed59e53b4 --- /dev/null +++ b/vtkm/filter/geometry_refinement/Shrink.cxx @@ -0,0 +1,65 @@ +//============================================================================ +// 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 + +namespace +{ +VTKM_CONT bool DoMapField(vtkm::cont::DataSet& result, + const vtkm::cont::Field& inputField, + const vtkm::cont::ArrayHandle& outputToInputCellMap) +{ + if (inputField.IsCellField() || inputField.IsWholeDataSetField()) + { + result.AddField(inputField); // pass through + return true; + } + else if (inputField.IsPointField()) + { + return vtkm::filter::MapFieldPermutation(inputField, outputToInputCellMap, result); + } + else + { + return false; + } +} +} // anonymous namespace + +namespace vtkm +{ +namespace filter +{ +namespace geometry_refinement +{ +VTKM_CONT vtkm::cont::DataSet Shrink::DoExecute(const vtkm::cont::DataSet& input) +{ + const vtkm::cont::UnknownCellSet& inCellSet = input.GetCellSet(); + const auto& oldCoords = input.GetCoordinateSystem().GetDataAsMultiplexer(); + + vtkm::cont::ArrayHandle newCoords; + vtkm::cont::ArrayHandle oldPointsMapping; + vtkm::cont::CellSetExplicit<> newCellset; + vtkm::worklet::Shrink worklet; + + worklet.Run(inCellSet, this->ShrinkFactor, oldCoords, newCoords, oldPointsMapping, newCellset); + + auto mapper = [&](auto& result, const auto& f) { DoMapField(result, f, oldPointsMapping); }; + + vtkm::cont::CoordinateSystem activeCoordSystem = input.GetCoordinateSystem(); + activeCoordSystem = vtkm::cont::CoordinateSystem(activeCoordSystem.GetName(), newCoords); + + return this->CreateResultCoordinateSystem(input, newCellset, activeCoordSystem, mapper); +} +} // namespace geometry_refinement +} // namespace filter +} // namespace vtkm diff --git a/vtkm/filter/geometry_refinement/Shrink.h b/vtkm/filter/geometry_refinement/Shrink.h new file mode 100644 index 000000000..173865f1c --- /dev/null +++ b/vtkm/filter/geometry_refinement/Shrink.h @@ -0,0 +1,48 @@ +//============================================================================ +// 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_geometry_refinement_Shrink_h +#define vtk_m_filter_geometry_refinement_Shrink_h + +#include +#include + +namespace vtkm +{ +namespace filter +{ +namespace geometry_refinement +{ +/// \brief Shrink cells of an arbitrary dataset by a constant factor +/// The Shrink filter shrinks the cells of a DataSet towards their centroid, +/// computed as the average position of the cell points. +/// This filter disconnects the cells, duplicating the points connected to multiple cells. +/// The resulting CellSet is always an `ExplicitCellSet`. +class VTKM_FILTER_GEOMETRY_REFINEMENT_EXPORT Shrink : public vtkm::filter::FilterField +{ +public: + VTKM_CONT + void SetShrinkFactor(const vtkm::FloatDefault& factor) + { + this->ShrinkFactor = vtkm::Min(vtkm::Max(0, factor), 1); // Clamp shrink factor value + } + + VTKM_CONT + const vtkm::FloatDefault& GetShrinkFactor() const { return this->ShrinkFactor; } + +private: + VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override; + vtkm::FloatDefault ShrinkFactor = 0.5f; +}; +} // namespace geometry_refinement +} // namespace filter +} // namespace vtkm + +#endif // vtk_m_filter_geometry_refinement_Shrink_h diff --git a/vtkm/filter/geometry_refinement/testing/CMakeLists.txt b/vtkm/filter/geometry_refinement/testing/CMakeLists.txt index 98f75c805..3e563d003 100644 --- a/vtkm/filter/geometry_refinement/testing/CMakeLists.txt +++ b/vtkm/filter/geometry_refinement/testing/CMakeLists.txt @@ -9,6 +9,7 @@ ##============================================================================ set(unit_tests + UnitTestShrinkFilter.cxx UnitTestSplitSharpEdgesFilter.cxx UnitTestTetrahedralizeFilter.cxx UnitTestTriangulateFilter.cxx diff --git a/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx b/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx new file mode 100644 index 000000000..ff88c443d --- /dev/null +++ b/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx @@ -0,0 +1,169 @@ +//============================================================================ +// 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 + +using vtkm::cont::testing::MakeTestDataSet; + +namespace +{ + +const std::array expectedPointVar{ + { 10.1f, 20.1f, 30.2f, 30.2f, 20.1f, 40.2f, 50.3f } +}; + +const std::array expectedConnectivityArray{ { 0, 1, 2, 3, 4, 5, 6 } }; + +const vtkm::Vec3f expectedCoords[7]{ { 0.333333f, 0.166666f, 0.0f }, { 0.833333f, 0.166666f, 0.0f }, + { 0.833333f, 0.666666f, 0.0f }, { 1.25f, 1.0f, 0.0f }, + { 1.25f, 0.5f, 0.0f }, { 1.75f, 1.0f, 0.0f }, + { 1.75f, 1.5f, 0.0f } }; + +const vtkm::FloatDefault expectedPointValueCube1[8]{ 10.1f, 20.1f, 50.2f, 40.1f, + 70.2f, 80.2f, 110.3f, 100.3f }; +const vtkm::Vec3f expectedCoordsCell1[8]{ { 0.4f, 0.4f, 0.4f }, { 0.6f, 0.4f, 0.4f }, + { 0.6f, 0.6f, 0.4f }, { 0.4f, 0.6f, 0.4f }, + { 0.4f, 0.4f, 0.6f }, { 0.6f, 0.4f, 0.6f }, + { 0.6f, 0.6f, 0.6f }, { 0.4f, 0.6f, 0.6f } }; + + +void TestWithExplicitData() +{ + vtkm::cont::DataSet dataSet = MakeTestDataSet().Make3DExplicitDataSet0(); + + vtkm::filter::geometry_refinement::Shrink shrink; + shrink.SetFieldsToPass({ "pointvar", "cellvar" }); + + VTKM_TEST_ASSERT(test_equal(shrink.GetShrinkFactor(), 0.5f), "Wrong shrink factor default value"); + + // Test shrink factor clamping + shrink.SetShrinkFactor(1.5f); + VTKM_TEST_ASSERT(test_equal(shrink.GetShrinkFactor(), 1.0f), "Shrink factor not limited to 1"); + + shrink.SetShrinkFactor(-0.5f); + VTKM_TEST_ASSERT(test_equal(shrink.GetShrinkFactor(), 0.0f), + "Shrink factor is not always positive"); + + shrink.SetShrinkFactor(0.5f); + + vtkm::cont::DataSet output = shrink.Execute(dataSet); + VTKM_TEST_ASSERT(test_equal(output.GetNumberOfCells(), dataSet.GetNumberOfCells()), + "Wrong number of cells for Shrink filter"); + VTKM_TEST_ASSERT(test_equal(output.GetNumberOfPoints(), 7), "Wrong number of points for Shrink"); + + + vtkm::cont::ArrayHandle outCellData = + output.GetField("cellvar").GetData().AsArrayHandle>(); + + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(0), 100.1f), "Wrong cell field data"); + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(1), 100.2f), "Wrong cell field data"); + + vtkm::cont::ArrayHandle outPointData = + output.GetField("pointvar").GetData().AsArrayHandle>(); + + for (vtkm::IdComponent i = 0; i < outPointData.GetNumberOfValues(); i++) + { + VTKM_TEST_ASSERT(test_equal(outPointData.ReadPortal().Get(i), expectedPointVar[i]), + "Wrong point field data"); + } + + const auto& connectivityArray = + output.GetCellSet().AsCellSet>().GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + auto connectivityArrayPortal = connectivityArray.ReadPortal(); + + for (vtkm::IdComponent i = 0; i < connectivityArray.GetNumberOfValues(); i++) + { + VTKM_TEST_ASSERT(test_equal(connectivityArrayPortal.Get(i), expectedConnectivityArray[i]), + "Wrong connectivity array value"); + } + + auto newCoords = output.GetCoordinateSystem().GetDataAsMultiplexer(); + auto newCoordsP = newCoords.ReadPortal(); + + for (vtkm::IdComponent i = 0; i < newCoords.GetNumberOfValues(); i++) + { + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[0], expectedCoords[i][0]), + "Wrong point coordinates"); + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[1], expectedCoords[i][1]), + "Wrong point coordinates"); + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[2], expectedCoords[i][2]), + "Wrong point coordinates"); + } +} + + +void TestWithUniformData() +{ + vtkm::cont::DataSet dataSet = MakeTestDataSet().Make3DUniformDataSet0(); + + vtkm::filter::geometry_refinement::Shrink shrink; + shrink.SetFieldsToPass({ "pointvar", "cellvar" }); + + shrink.SetShrinkFactor(0.2f); + + vtkm::cont::DataSet output = shrink.Execute(dataSet); + + VTKM_TEST_ASSERT(test_equal(output.GetNumberOfCells(), dataSet.GetNumberOfCells()), + "Number of cells changed after filtering"); + VTKM_TEST_ASSERT(test_equal(output.GetNumberOfPoints(), 4 * 8), "Wrong number of points"); + + vtkm::cont::ArrayHandle outCellData = + output.GetField("cellvar").GetData().AsArrayHandle>(); + + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(0), 100.1), "Wrong cell field data"); + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(1), 100.2), "Wrong cell field data"); + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(2), 100.3), "Wrong cell field data"); + VTKM_TEST_ASSERT(test_equal(outCellData.ReadPortal().Get(3), 100.4), "Wrong cell field data"); + + vtkm::cont::ArrayHandle outPointData = + output.GetField("pointvar").GetData().AsArrayHandle>(); + + for (vtkm::IdComponent i = 0; i < 8; i++) // Test for the first cell only + { + VTKM_TEST_ASSERT(test_equal(outPointData.ReadPortal().Get(i), expectedPointValueCube1[i]), + "Wrong cell field data"); + } + + auto newCoords = output.GetCoordinateSystem().GetDataAsMultiplexer(); + auto newCoordsP = newCoords.ReadPortal(); + + for (vtkm::IdComponent i = 0; i < 8; i++) + { + std::cout << newCoordsP.Get(i)[0] << " " << expectedCoordsCell1[i][0] << std::endl; + std::cout << newCoordsP.Get(i)[1] << " " << expectedCoordsCell1[i][1] << std::endl; + std::cout << newCoordsP.Get(i)[2] << " " << expectedCoordsCell1[i][2] << std::endl; + + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[0], expectedCoordsCell1[i][0]), + "Wrong point coordinates"); + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[1], expectedCoordsCell1[i][1]), + "Wrong point coordinates"); + VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[2], expectedCoordsCell1[i][2]), + "Wrong point coordinates"); + } +} + + +void TestShrinkFilter() +{ + TestWithExplicitData(); + TestWithUniformData(); +} + +} // anonymous namespace + +int UnitTestShrinkFilter(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(TestShrinkFilter, argc, argv); +} diff --git a/vtkm/filter/geometry_refinement/worklet/CMakeLists.txt b/vtkm/filter/geometry_refinement/worklet/CMakeLists.txt index 7124cb6f2..a81485a76 100644 --- a/vtkm/filter/geometry_refinement/worklet/CMakeLists.txt +++ b/vtkm/filter/geometry_refinement/worklet/CMakeLists.txt @@ -9,6 +9,7 @@ ##============================================================================ set(headers + Shrink.h SplitSharpEdges.h Tetrahedralize.h Triangulate.h diff --git a/vtkm/filter/geometry_refinement/worklet/Shrink.h b/vtkm/filter/geometry_refinement/worklet/Shrink.h new file mode 100644 index 000000000..5d2a6c5bb --- /dev/null +++ b/vtkm/filter/geometry_refinement/worklet/Shrink.h @@ -0,0 +1,150 @@ +//============================================================================ +// 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_worklet_Shrink_h +#define vtk_m_worklet_Shrink_h + +#include +#include + +#include +#include +#include + + +namespace vtkm +{ +namespace worklet +{ +class Shrink +{ +public: + struct PrepareCellsForShrink : vtkm::worklet::WorkletVisitCellsWithPoints + { + using ControlSignature = void(CellSetIn, + FieldOutCell numPoints, + FieldOutCell centroids, + FieldOutCell shapes, + FieldInPoint coords); + using ExecutionSignature = + void(PointCount, _2 numPoints, _3 centroids, _4 shapes, _5 coords, CellShape); + + using InputDomain = _1; + + template + VTKM_EXEC void operator()(vtkm::IdComponent numPointsInCell, + vtkm::IdComponent& numPoints, + vtkm::Vec3f& centroids, + ShapeIdType& shapes, + const CoordsArrayType& coords, + ShapeTagType cellShape) const + { + numPoints = numPointsInCell; + shapes = cellShape.Id; + + vtkm::Vec3f cellCenter; + vtkm::exec::ParametricCoordinatesCenter(numPoints, cellShape, cellCenter); + vtkm::exec::CellInterpolate(coords, cellCenter, cellShape, centroids); + } + }; + + struct ComputeNewPoints : vtkm::worklet::WorkletVisitCellsWithPoints + { + ComputeNewPoints(vtkm::FloatDefault shrinkFactor) + : ShrinkFactor(shrinkFactor) + { + } + using ControlSignature = void(CellSetIn, + FieldInCell offsets, + FieldInCell centroids, + FieldOutCell oldPointsMapping, + FieldOutCell newPoints, + FieldOutCell newCoords, + FieldInPoint coords); + using ExecutionSignature = void(_2 offsets, + _3 centroids, + _4 oldPointsMapping, + _5 newPoints, + _6 newCoords, + _7 coords, + VisitIndex localPointNum, + PointIndices globalPointIndex); + using InputDomain = _1; + + using ScatterType = vtkm::worklet::ScatterCounting; + + template + VTKM_EXEC void operator()(const vtkm::Id& offsets, + const vtkm::Vec3f& centroids, + vtkm::Id& oldPointsMapping, + vtkm::Id& newPoints, + CoordsArrayTypeOut& newCoords, + const CoordsArrayTypeIn& coords, + vtkm::IdComponent localPtIndex, + const PointIndicesVecType& globalPointIndex) const + { + newPoints = offsets + localPtIndex; + oldPointsMapping = globalPointIndex[localPtIndex]; + newCoords = centroids + this->ShrinkFactor * (coords[localPtIndex] - centroids); + } + + private: + vtkm::FloatDefault ShrinkFactor; + }; + + template + void Run( + const CellSetType& oldCellset, + const vtkm::FloatDefault shinkFactor, + const vtkm::cont::ArrayHandle, CoordsInStorageType>& oldCoords, + vtkm::cont::ArrayHandle, CoordsOutStorageType>& newCoords, + vtkm::cont::ArrayHandle& oldPointsMapping, + NewCellSetType& newCellset) + { + vtkm::cont::Invoker invoke; + + // First pass : count the new number of points per cell, shapes and compute centroids + vtkm::cont::ArrayHandle CellPointCount; + vtkm::cont::ArrayHandle Centroids; + vtkm::cont::CellSetExplicit<>::ShapesArrayType shapeArray; + invoke(PrepareCellsForShrink{}, oldCellset, CellPointCount, Centroids, shapeArray, oldCoords); + + + // Second pass : compute new point positions and mappings to input points + vtkm::cont::ArrayHandle newPoints; + vtkm::worklet::ScatterCounting scatter(CellPointCount, true); + vtkm::cont::ArrayHandle offsets = scatter.GetInputToOutputMap(); + vtkm::Id totalPoints = scatter.GetOutputRange(CellPointCount.GetNumberOfValues()); + + ComputeNewPoints worklet = ComputeNewPoints(shinkFactor); + invoke(worklet, + scatter, + oldCellset, + offsets, + Centroids, + oldPointsMapping, + newPoints, + newCoords, + oldCoords); + + newCellset.Fill(totalPoints, + shapeArray, + newPoints, + vtkm::cont::ConvertNumComponentsToOffsets(CellPointCount)); + } +}; +} // namespace vtkm::worklet +} // namespace vtkm + +#endif // vtk_m_worklet_Shrink_h From b4a6c2b546d1d82baf9570cfc36adb336304460f Mon Sep 17 00:00:00 2001 From: Mark Bolstad Date: Wed, 8 Mar 2023 12:22:49 -0700 Subject: [PATCH 43/64] Restore argument processing to InSitu benchmark GBench barfs on arguments such as --size without this patch that restores removing vtkm specific arguments from the command-line. --- benchmarking/BenchmarkInSitu.cxx | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index 5c59b7d9c..4854b7ccc 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -984,6 +984,55 @@ void ParseBenchmarkOptions(int& argc, char** argv) std::cerr << "Using data set dimensions = " << DataSetDim << std::endl; std::cerr << "Using image size = " << ImageSize << "x" << ImageSize << std::endl; + + // Now go back through the arg list and remove anything that is not in the list of + // unknown options or non-option arguments. + int destArg = 1; + // This is copy/pasted from vtkm::cont::Initialize(), should probably be abstracted eventually: + for (int srcArg = 1; srcArg < argc; ++srcArg) + { + std::string thisArg{ argv[srcArg] }; + bool copyArg = false; + + // Special case: "--" gets removed by optionparser but should be passed. + if (thisArg == "--") + { + copyArg = true; + } + for (const option::Option* opt = options[UNKNOWN]; !copyArg && opt != nullptr; + opt = opt->next()) + { + if (thisArg == opt->name) + { + copyArg = true; + } + if ((opt->arg != nullptr) && (thisArg == opt->arg)) + { + copyArg = true; + } + // Special case: optionparser sometimes removes a single "-" from an option + if (thisArg.substr(1) == opt->name) + { + copyArg = true; + } + } + for (int nonOpt = 0; !copyArg && nonOpt < commandLineParse.nonOptionsCount(); ++nonOpt) + { + if (thisArg == commandLineParse.nonOption(nonOpt)) + { + copyArg = true; + } + } + if (copyArg) + { + if (destArg != srcArg) + { + argv[destArg] = argv[srcArg]; + } + ++destArg; + } + } + argc = destArg; } } // end anon namespace From ea13c27613d6026653d38778da4810904eb74598 Mon Sep 17 00:00:00 2001 From: Louis Gombert Date: Thu, 9 Mar 2023 16:46:58 +0100 Subject: [PATCH 44/64] Minor Shrink filter fixes --- vtkm/filter/geometry_refinement/worklet/Shrink.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vtkm/filter/geometry_refinement/worklet/Shrink.h b/vtkm/filter/geometry_refinement/worklet/Shrink.h index 5d2a6c5bb..a412d9b26 100644 --- a/vtkm/filter/geometry_refinement/worklet/Shrink.h +++ b/vtkm/filter/geometry_refinement/worklet/Shrink.h @@ -115,24 +115,24 @@ public: vtkm::cont::Invoker invoke; // First pass : count the new number of points per cell, shapes and compute centroids - vtkm::cont::ArrayHandle CellPointCount; - vtkm::cont::ArrayHandle Centroids; + vtkm::cont::ArrayHandle cellPointCount; + vtkm::cont::ArrayHandle centroids; vtkm::cont::CellSetExplicit<>::ShapesArrayType shapeArray; - invoke(PrepareCellsForShrink{}, oldCellset, CellPointCount, Centroids, shapeArray, oldCoords); + invoke(PrepareCellsForShrink{}, oldCellset, cellPointCount, centroids, shapeArray, oldCoords); // Second pass : compute new point positions and mappings to input points vtkm::cont::ArrayHandle newPoints; - vtkm::worklet::ScatterCounting scatter(CellPointCount, true); + vtkm::worklet::ScatterCounting scatter(cellPointCount, true); vtkm::cont::ArrayHandle offsets = scatter.GetInputToOutputMap(); - vtkm::Id totalPoints = scatter.GetOutputRange(CellPointCount.GetNumberOfValues()); + vtkm::Id totalPoints = scatter.GetOutputRange(cellPointCount.GetNumberOfValues()); ComputeNewPoints worklet = ComputeNewPoints(shinkFactor); invoke(worklet, scatter, oldCellset, offsets, - Centroids, + centroids, oldPointsMapping, newPoints, newCoords, @@ -141,7 +141,7 @@ public: newCellset.Fill(totalPoints, shapeArray, newPoints, - vtkm::cont::ConvertNumComponentsToOffsets(CellPointCount)); + vtkm::cont::ConvertNumComponentsToOffsets(cellPointCount)); } }; } // namespace vtkm::worklet From 5aba6e1beac3dcc7ef3d061add5014cb27dbe6e9 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 13 Mar 2023 13:38:01 -0600 Subject: [PATCH 45/64] Remove unlicensed data Some of the test data sets are derived from data sets that are commonly distributed to test visualization algorithms and are featured in numerous papers. However, I am unable to track down the original source let alone identify what license, if any, they were released under. To avoid any complications with data ownership, remove these data sets and replace them with in house data sets that we explicitly own. --- data/data/curvilinear/kitchen.vtk | 3 + data/data/rectilinear/fishtank.vtk | 3 - .../rectilinear/fishtank_double_ascii.vtk | 3 - .../fishtank_double_big_endian.vtk | 3 - data/data/rectilinear/fusion.vtk | 3 - data/data/rectilinear/magField.vtk | 3 - data/data/uniform/rotate-vectors.vtk | 3 + .../particle_advection/ParticleAdvection.cxx | 10 +- examples/streamline_mpi/StreamlineMPI.cxx | 6 +- .../flow/testing/UnitTestStreamlineFilter.cxx | 96 +++--- .../UnitTestWorkletParticleAdvection.cxx | 66 ++-- vtkm/io/testing/UnitTestVTKDataSetReader.cxx | 307 +++++------------- 12 files changed, 187 insertions(+), 319 deletions(-) create mode 100644 data/data/curvilinear/kitchen.vtk delete mode 100644 data/data/rectilinear/fishtank.vtk delete mode 100644 data/data/rectilinear/fishtank_double_ascii.vtk delete mode 100644 data/data/rectilinear/fishtank_double_big_endian.vtk delete mode 100644 data/data/rectilinear/fusion.vtk delete mode 100644 data/data/rectilinear/magField.vtk create mode 100644 data/data/uniform/rotate-vectors.vtk diff --git a/data/data/curvilinear/kitchen.vtk b/data/data/curvilinear/kitchen.vtk new file mode 100644 index 000000000..c9455842d --- /dev/null +++ b/data/data/curvilinear/kitchen.vtk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:29d6de0eb33dfb792405d3903b1ede382cac417c29bb5d7e17e60be384db42cc +size 1940269 diff --git a/data/data/rectilinear/fishtank.vtk b/data/data/rectilinear/fishtank.vtk deleted file mode 100644 index e1ab1c481..000000000 --- a/data/data/rectilinear/fishtank.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ef3dfd79f0c8d18780d0749014d71c0226134041283d33de0bcd994e343dd421 -size 2001070 diff --git a/data/data/rectilinear/fishtank_double_ascii.vtk b/data/data/rectilinear/fishtank_double_ascii.vtk deleted file mode 100644 index fce0d5b9c..000000000 --- a/data/data/rectilinear/fishtank_double_ascii.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2bb3d36ea5ecef5e7ef1057d0dddebbc590424915083091ead3dac2928000524 -size 2904465 diff --git a/data/data/rectilinear/fishtank_double_big_endian.vtk b/data/data/rectilinear/fishtank_double_big_endian.vtk deleted file mode 100644 index 7ecfbc133..000000000 --- a/data/data/rectilinear/fishtank_double_big_endian.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bffad7dae3dd6ef018ad7a9e109464ced0f3b9bc15cf1fb5d555f6d0d00b621f -size 3001624 diff --git a/data/data/rectilinear/fusion.vtk b/data/data/rectilinear/fusion.vtk deleted file mode 100644 index 5c5212da1..000000000 --- a/data/data/rectilinear/fusion.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2cbdf56fd5445ddc5b6bc05507b8825fb8d74fe1ccce894bde03e5ff2ecf5fb6 -size 525141 diff --git a/data/data/rectilinear/magField.vtk b/data/data/rectilinear/magField.vtk deleted file mode 100644 index a79db3589..000000000 --- a/data/data/rectilinear/magField.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b947d66dbae99a1ebb392b200a9ea0d380cfccb7fcb3a3739615d0dde558d2f1 -size 238166 diff --git a/data/data/uniform/rotate-vectors.vtk b/data/data/uniform/rotate-vectors.vtk new file mode 100644 index 000000000..f1d45e33e --- /dev/null +++ b/data/data/uniform/rotate-vectors.vtk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13241631e0d65d17d7bad2be44b52c0352797135fb585647f5c821e439ff9817 +size 862894 diff --git a/examples/particle_advection/ParticleAdvection.cxx b/examples/particle_advection/ParticleAdvection.cxx index cc2885918..f56240897 100644 --- a/examples/particle_advection/ParticleAdvection.cxx +++ b/examples/particle_advection/ParticleAdvection.cxx @@ -16,11 +16,11 @@ #include // Example computing streamlines. -// An example vector field is available in the vtk-m data directory: magField.vtk +// An example vector field is available in the vtk-m data directory: rotate-vectors.vtk // Example usage: -// this will advect 200 particles 50 steps using a step size of 0.01 +// this will advect 200 particles 50 steps using a step size of 0.05 // -// Particle_Advection /magField.vtk vec 200 50 0.01 output.vtk +// Particle_Advection /rotate-vectors.vtk rotate 200 50 0.05 output.vtk // int main(int argc, char** argv) @@ -28,10 +28,10 @@ int main(int argc, char** argv) auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice; auto config = vtkm::cont::Initialize(argc, argv, opts); - if (argc < 8) + if (argc < 7) { std::cerr << "Usage: " << argv[0] - << "dataFile varName numSeeds numSteps stepSize outputFile [options]" << std::endl; + << " dataFile varName numSeeds numSteps stepSize outputFile [options]" << std::endl; std::cerr << "where options are: " << std::endl << config.Usage << std::endl; return -1; } diff --git a/examples/streamline_mpi/StreamlineMPI.cxx b/examples/streamline_mpi/StreamlineMPI.cxx index aec518cec..273340898 100644 --- a/examples/streamline_mpi/StreamlineMPI.cxx +++ b/examples/streamline_mpi/StreamlineMPI.cxx @@ -76,11 +76,11 @@ void LoadData(std::string& fname, std::vector& dataSets, in } // Example computing streamlines. -// An example vector field is available in the vtk-m data directory: magField.vtk +// An example vector field is available in the vtk-m data directory: rotate-vectors.vtk // Example usage: -// this will advect 200 particles 50 steps using a step size of 0.01 +// this will advect 200 particles 50 steps using a step size of 0.05 // -// Particle_Advection /magField.vtk vec 200 50 0.01 output.vtk +// Particle_Advection /rotate-vectors.vtk vec 200 50 0.05 output.vtk // int main(int argc, char** argv) diff --git a/vtkm/filter/flow/testing/UnitTestStreamlineFilter.cxx b/vtkm/filter/flow/testing/UnitTestStreamlineFilter.cxx index 34116f632..7928e6e1c 100644 --- a/vtkm/filter/flow/testing/UnitTestStreamlineFilter.cxx +++ b/vtkm/filter/flow/testing/UnitTestStreamlineFilter.cxx @@ -513,24 +513,25 @@ void ValidateEndPoints(const CellSetType& cellSet, } } -void TestStreamlineFile(const std::string& fname, +void TestStreamlineFile(const std::string& fileName, + const std::string& fieldName, const std::vector& pts, vtkm::FloatDefault stepSize, vtkm::Id maxSteps, const std::vector& endPts, bool useSL) { - vtkm::io::VTKDataSetReader reader(fname); + vtkm::io::VTKDataSetReader reader(fileName); vtkm::cont::DataSet ds; try { ds = reader.ReadDataSet(); - VTKM_TEST_ASSERT(ds.HasField("vec")); + VTKM_TEST_ASSERT(ds.HasField(fieldName)); } catch (vtkm::io::ErrorIO& e) { std::string message("Error reading: "); - message += fname; + message += fileName; message += ", "; message += e.GetMessage(); @@ -550,7 +551,7 @@ void TestStreamlineFile(const std::string& fname, streamline.SetStepSize(stepSize); streamline.SetNumberOfSteps(maxSteps); streamline.SetSeeds(seedArray); - streamline.SetActiveField("vec"); + streamline.SetActiveField(fieldName); output = streamline.Execute(ds); } else @@ -559,7 +560,7 @@ void TestStreamlineFile(const std::string& fname, particleAdvection.SetStepSize(stepSize); particleAdvection.SetNumberOfSteps(maxSteps); particleAdvection.SetSeeds(seedArray); - particleAdvection.SetActiveField("vec"); + particleAdvection.SetActiveField(fieldName); output = particleAdvection.Execute(ds); } @@ -604,48 +605,59 @@ void TestStreamlineFilters() for (auto useSL : flags) TestAMRStreamline(useSL); - //Fusion test. - std::vector 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 = vtkm::cont::testing::Testing::DataPath("rectilinear/fusion.vtk"); + { + //Rotate test. + std::vector startPoints, endPoints; + startPoints.push_back(vtkm::Vec3f(0.4f, 0.3f, -0.2f)); + startPoints.push_back(vtkm::Vec3f(-0.4f, 0.0f, -0.84f)); + startPoints.push_back(vtkm::Vec3f(0.0f, 0.0f, 0.41f)); + //End point values were generated in VisIt. + endPoints.push_back(vtkm::Vec3f(-0.341196f, 0.474331f, 0.142614f)); + endPoints.push_back(vtkm::Vec3f(-0.342764f, -0.713572f, -0.746209f)); + endPoints.push_back(vtkm::Vec3f(-0.617492f, -0.0167f, 0.104733f)); + vtkm::FloatDefault stepSize = 0.1f; + std::string file = vtkm::cont::testing::Testing::DataPath("uniform/rotate-vectors.vtk"); - for (auto useSL : flags) - TestStreamlineFile(fusionFile, fusionPts, fusionStep, 1000, fusionEndPts, useSL); + for (auto useSL : flags) + { + TestStreamlineFile(file, "rotate", startPoints, stepSize, 1000, endPoints, useSL); + } + } - //Fishtank test. - std::vector 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 = vtkm::cont::testing::Testing::DataPath("rectilinear/fishtank.vtk"); + { + //Kitchen test. + std::vector startPoints, endPoints; + startPoints.push_back(vtkm::Vec3f(6.0f, 1.0f, 2.0f)); + startPoints.push_back(vtkm::Vec3f(1.3f, 2.4f, 1.3f)); + startPoints.push_back(vtkm::Vec3f(1.0f, 3.0f, 2.0f)); + //End point values were generated in VisIt. + endPoints.push_back(vtkm::Vec3f(4.42419f, 0.956935f, 1.89111f)); + endPoints.push_back(vtkm::Vec3f(0.217019f, 3.65243f, 2.49638f)); + endPoints.push_back(vtkm::Vec3f(0.753178f, 0.410568f, 1.11006f)); + vtkm::FloatDefault stepSize = 0.2f; + std::string file = vtkm::cont::testing::Testing::DataPath("curvilinear/kitchen.vtk"); - for (auto useSL : flags) - TestStreamlineFile(fishFile, fishPts, fishStep, 100, fishEndPts, useSL); + for (auto useSL : flags) + { + TestStreamlineFile(file, "velocity", startPoints, stepSize, 2000, endPoints, useSL); + } + } - //ARMWind corner case of particle near boundary. - std::string amrWindFile = - vtkm::cont::testing::Testing::DataPath("rectilinear/amr_wind_flowfield.vtk"); - vtkm::FloatDefault amrWindStep = 0.001f; - std::vector amrWindPts, amrWindEndPts; + { + //ARMWind corner case of particle near boundary. + std::string file = vtkm::cont::testing::Testing::DataPath("rectilinear/amr_wind_flowfield.vtk"); + vtkm::FloatDefault stepSize = 0.001f; + std::vector startPoints, endPoints; - amrWindPts.push_back( - vtkm::Vec3f(0.053217993470017745f, 0.034506499099396459f, 0.057097713925011492f)); - amrWindEndPts.push_back(vtkm::Vec3f(0.05712112784f, 0.03450008854f, 0.02076501213f)); + startPoints.push_back( + vtkm::Vec3f(0.053217993470017745f, 0.034506499099396459f, 0.057097713925011492f)); + endPoints.push_back(vtkm::Vec3f(0.05712112784f, 0.03450008854f, 0.02076501213f)); - for (auto useSL : flags) - TestStreamlineFile(amrWindFile, amrWindPts, amrWindStep, 10000, amrWindEndPts, useSL); + for (auto useSL : flags) + { + TestStreamlineFile(file, "vec", startPoints, stepSize, 10000, endPoints, useSL); + } + } } } diff --git a/vtkm/filter/flow/testing/UnitTestWorkletParticleAdvection.cxx b/vtkm/filter/flow/testing/UnitTestWorkletParticleAdvection.cxx index fafcbea42..1ac75c5a7 100644 --- a/vtkm/filter/flow/testing/UnitTestWorkletParticleAdvection.cxx +++ b/vtkm/filter/flow/testing/UnitTestWorkletParticleAdvection.cxx @@ -839,15 +839,16 @@ void ValidateResult(const ResultType& res, } -void TestParticleAdvectionFile(const std::string& fname, +void TestParticleAdvectionFile(const std::string& fileName, + const std::string& fieldName, const std::vector& pts, vtkm::FloatDefault stepSize, vtkm::Id maxSteps, const std::vector& endPts) { - VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing particle advection on file " << fname); - vtkm::io::VTKDataSetReader reader(fname); + VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing particle advection on file " << fileName); + vtkm::io::VTKDataSetReader reader(fileName); vtkm::cont::DataSet ds; try { @@ -856,7 +857,7 @@ void TestParticleAdvectionFile(const std::string& fname, catch (vtkm::io::ErrorIO& e) { std::string message("Error reading: "); - message += fname; + message += fileName; message += ", "; message += e.GetMessage(); @@ -869,8 +870,8 @@ void TestParticleAdvectionFile(const std::string& fname, using RK4Type = vtkm::worklet::flow::RK4Integrator; using Stepper = vtkm::worklet::flow::Stepper; - VTKM_TEST_ASSERT(ds.HasField("vec"), "Data set missing a field named 'vec'"); - vtkm::cont::Field& field = ds.GetField("vec"); + VTKM_TEST_ASSERT(ds.HasField(fieldName), "Data set missing a field named ", fieldName); + vtkm::cont::Field& field = ds.GetField(fieldName); auto fieldData = field.GetData(); FieldHandle fieldArray; @@ -923,32 +924,35 @@ void TestParticleAdvection() TestWorkletsBasic(); TestParticleWorkletsWithDataSetTypes(); - //Fusion test. - std::vector 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 = vtkm::cont::testing::Testing::DataPath("rectilinear/fusion.vtk"); - TestParticleAdvectionFile(fusionFile, fusionPts, fusionStep, 1000, fusionEndPts); + { + //Rotate test. + std::vector startPoints, endPoints; + startPoints.push_back(vtkm::Vec3f(0.4f, 0.3f, -0.2f)); + startPoints.push_back(vtkm::Vec3f(-0.4f, 0.0f, -0.84f)); + startPoints.push_back(vtkm::Vec3f(0.0f, 0.0f, 0.41f)); + //End point values were generated in VisIt. + endPoints.push_back(vtkm::Vec3f(-0.341196f, 0.474331f, 0.142614f)); + endPoints.push_back(vtkm::Vec3f(-0.342764f, -0.713572f, -0.746209f)); + endPoints.push_back(vtkm::Vec3f(-0.617492f, -0.0167f, 0.104733f)); + vtkm::FloatDefault stepSize = 0.1f; + std::string file = vtkm::cont::testing::Testing::DataPath("uniform/rotate-vectors.vtk"); + TestParticleAdvectionFile(file, "rotate", startPoints, stepSize, 1000, endPoints); + } - //Fishtank test. - std::vector 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 = vtkm::cont::testing::Testing::DataPath("rectilinear/fishtank.vtk"); - TestParticleAdvectionFile(fishFile, fishPts, fishStep, 100, fishEndPts); + { + //Kitchen test. + std::vector startPoints, endPoints; + startPoints.push_back(vtkm::Vec3f(6.0f, 1.0f, 2.0f)); + startPoints.push_back(vtkm::Vec3f(1.3f, 2.4f, 1.3f)); + startPoints.push_back(vtkm::Vec3f(1.0f, 3.0f, 2.0f)); + //End point values were generated in VisIt. + endPoints.push_back(vtkm::Vec3f(4.42419f, 0.956935f, 1.89111f)); + endPoints.push_back(vtkm::Vec3f(0.217019f, 3.65243f, 2.49638f)); + endPoints.push_back(vtkm::Vec3f(0.753178f, 0.410568f, 1.11006f)); + vtkm::FloatDefault stepSize = 0.2f; + std::string file = vtkm::cont::testing::Testing::DataPath("curvilinear/kitchen.vtk"); + TestParticleAdvectionFile(file, "velocity", startPoints, stepSize, 2000, endPoints); + } } int UnitTestWorkletParticleAdvection(int argc, char* argv[]) diff --git a/vtkm/io/testing/UnitTestVTKDataSetReader.cxx b/vtkm/io/testing/UnitTestVTKDataSetReader.cxx index 7270ddffc..edefc4ca7 100644 --- a/vtkm/io/testing/UnitTestVTKDataSetReader.cxx +++ b/vtkm/io/testing/UnitTestVTKDataSetReader.cxx @@ -368,250 +368,115 @@ void TestReadingStructuredGridBin() "Incorrect cellset type"); } -void TestReadingFishTank() +void TestReadingRotate() { - std::string fishtank = vtkm::cont::testing::Testing::DataPath("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>(), - "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() == 3, "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 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.IsPointField()); - - 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.IsPointField()); - // Bounds from Information panel: - // [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867] - const vtkm::cont::ArrayHandle& 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::DataPath("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>(), - "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 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.IsPointField()); - // Bounds from Information panel: - // [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867] - const vtkm::cont::ArrayHandle& 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::DataPath("rectilinear/fishtank_double_ascii.vtk"); - vtkm::cont::DataSet ds = readVTKDataSet(fishtank.c_str()); - VTKM_TEST_ASSERT(ds.GetCellSet().IsType>(), - "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 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.IsPointField()); - // Bounds from Paraview information panel: - // [-65.3147, 86.267], [-88.0325, 78.7217], [-67.0969, 156.867] - const vtkm::cont::ArrayHandle& 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::DataPath("rectilinear/fusion.vtk"); + std::string fusion = vtkm::cont::testing::Testing::DataPath("uniform/rotate-vectors.vtk"); vtkm::cont::DataSet ds = readVTKDataSet(fusion.c_str()); VTKM_TEST_ASSERT(ds.GetCellSet().IsType>(), "Incorrect cellset type"); - VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 32 * 32 * 32, "Incorrect number of points"); - VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 32 * 32 * 32, + VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 33 * 33 * 33, "Incorrect number of points"); + VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 33 * 33 * 33, "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."); + VTKM_TEST_ASSERT(ds.HasField("rotate"), + "The vtk file has a field 'rotate', but the dataset does not."); // Taken from Paraview + clicking Data Axes Grid: const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem(); vtkm::Vec ranges = coordinateSystem.GetRange(); vtkm::Range xRange = ranges[0]; - VTKM_TEST_ASSERT(xRange.Min == 0); + VTKM_TEST_ASSERT(xRange.Min == -1); VTKM_TEST_ASSERT(xRange.Max == 1); vtkm::Range yRange = ranges[1]; - VTKM_TEST_ASSERT(yRange.Min == 0); + VTKM_TEST_ASSERT(yRange.Min == -1); VTKM_TEST_ASSERT(yRange.Max == 1); vtkm::Range zRange = ranges[2]; - VTKM_TEST_ASSERT(zRange.Min == 0); + VTKM_TEST_ASSERT(zRange.Min == -1); 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.IsPointField()); - - 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"); + // rotate double [-1.29845, 1.25443], [-1.34447, 1.22820], [-0.32387, 0.33180] + vtkm::cont::Field vec = ds.GetField("rotate"); + VTKM_TEST_ASSERT(vec.GetName() == "rotate"); VTKM_TEST_ASSERT(vec.IsPointField()); const vtkm::cont::ArrayHandle& 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)); + VTKM_TEST_ASSERT(test_equal(xVecRange.Min, -1.29845)); + VTKM_TEST_ASSERT(test_equal(xVecRange.Max, 1.25443)); auto yVecRange = vecRangesReadPortal.Get(1); - VTKM_TEST_ASSERT(test_equal(yVecRange.Min, -3.41018)); - VTKM_TEST_ASSERT(test_equal(yVecRange.Max, 3.41036)); + VTKM_TEST_ASSERT(test_equal(yVecRange.Min, -1.34447)); + VTKM_TEST_ASSERT(test_equal(yVecRange.Max, 1.22820)); auto zVecRange = vecRangesReadPortal.Get(2); - VTKM_TEST_ASSERT(test_equal(zVecRange.Min, -0.689022)); - VTKM_TEST_ASSERT(test_equal(zVecRange.Max, 0.480726)); + VTKM_TEST_ASSERT(test_equal(zVecRange.Min, -0.32387)); + VTKM_TEST_ASSERT(test_equal(zVecRange.Max, 0.33180)); +} + +void TestReadingKitchen() +{ + std::string fusion = vtkm::cont::testing::Testing::DataPath("curvilinear/kitchen.vtk"); + vtkm::cont::DataSet ds = readVTKDataSet(fusion.c_str()); + + VTKM_TEST_ASSERT(ds.GetCellSet().IsType>(), + "Incorrect cellset type"); + VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 28 * 24 * 17, "Incorrect number of points"); + VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 28 * 24 * 17, + "Incorrect number of points (from cell set)"); + VTKM_TEST_ASSERT(ds.HasField("h1"), "The vtk file has a field 'h1', but the dataset does not."); + VTKM_TEST_ASSERT(ds.HasField("velocity"), + "The vtk file has a field 'velocity', but the dataset does not."); + + // Paraview Information Panel of this file: + // Bounds: [0.01, 7], [0.01, 5], [0.01, 2.5] + const vtkm::cont::CoordinateSystem& coordinateSystem = ds.GetCoordinateSystem(); + vtkm::Vec ranges = coordinateSystem.GetRange(); + vtkm::Range xRange = ranges[0]; + VTKM_TEST_ASSERT(test_equal(xRange.Min, 0.01)); + VTKM_TEST_ASSERT(test_equal(xRange.Max, 7)); + vtkm::Range yRange = ranges[1]; + VTKM_TEST_ASSERT(test_equal(yRange.Min, 0.01)); + VTKM_TEST_ASSERT(test_equal(yRange.Max, 5)); + vtkm::Range zRange = ranges[2]; + VTKM_TEST_ASSERT(test_equal(zRange.Min, 0.01)); + VTKM_TEST_ASSERT(test_equal(zRange.Max, 2.5)); + + // h1 float [0, 26823.6] + vtkm::cont::Field h1 = ds.GetField("h1"); + VTKM_TEST_ASSERT(h1.GetName() == "h1"); + VTKM_TEST_ASSERT(h1.IsPointField()); + const vtkm::cont::ArrayHandle& h1Ranges = h1.GetRange(); + VTKM_TEST_ASSERT(h1Ranges.GetNumberOfValues() == 1); + auto h1RangesReadPortal = h1Ranges.ReadPortal(); + + auto h1Range = h1RangesReadPortal.Get(0); + VTKM_TEST_ASSERT(test_equal(h1Range.Min, 0)); + VTKM_TEST_ASSERT(test_equal(h1Range.Max, 26823.6)); + + // velocity float [-0.34942, 0.26521], [-0.31407, 0.31543], [-0.45072, 0.28649] + vtkm::cont::Field vec = ds.GetField("velocity"); + VTKM_TEST_ASSERT(vec.GetName() == "velocity"); + VTKM_TEST_ASSERT(vec.IsPointField()); + const vtkm::cont::ArrayHandle& vecRanges = vec.GetRange(); + VTKM_TEST_ASSERT(vecRanges.GetNumberOfValues() == 3); + auto vecRangesReadPortal = vecRanges.ReadPortal(); + + auto xVecRange = vecRangesReadPortal.Get(0); + VTKM_TEST_ASSERT(test_equal(xVecRange.Min, -0.34942)); + VTKM_TEST_ASSERT(test_equal(xVecRange.Max, 0.26521)); + + auto yVecRange = vecRangesReadPortal.Get(1); + + VTKM_TEST_ASSERT(test_equal(yVecRange.Min, -0.31407)); + VTKM_TEST_ASSERT(test_equal(yVecRange.Max, 0.31543)); + + auto zVecRange = vecRangesReadPortal.Get(2); + VTKM_TEST_ASSERT(test_equal(zVecRange.Min, -0.45072)); + VTKM_TEST_ASSERT(test_equal(zVecRange.Max, 0.28649)); } void TestSkppingStringFields(Format format) @@ -668,14 +533,10 @@ 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(); + std::cout << "Test reading rotate" << std::endl; + TestReadingRotate(); + std::cout << "Test reading kitchen" << std::endl; + TestReadingKitchen(); std::cout << "Test skipping string fields in ASCII files" << std::endl; TestSkppingStringFields(FORMAT_ASCII); From f60f437000575a721bec4f0f6745651aaa089fb0 Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Mon, 13 Mar 2023 16:13:21 -0400 Subject: [PATCH 46/64] Add VisIt file reader. --- data/data/uniform/venn250.visit | 3 + vtkm/io/CMakeLists.txt | 2 + vtkm/io/VTKVisItFileReader.cxx | 99 +++++++++++++++++++ vtkm/io/VTKVisItFileReader.h | 39 ++++++++ vtkm/io/testing/CMakeLists.txt | 1 + .../UnitTestVisItFileDataSetReader.cxx | 60 +++++++++++ 6 files changed, 204 insertions(+) create mode 100644 data/data/uniform/venn250.visit create mode 100644 vtkm/io/VTKVisItFileReader.cxx create mode 100644 vtkm/io/VTKVisItFileReader.h create mode 100644 vtkm/io/testing/UnitTestVisItFileDataSetReader.cxx diff --git a/data/data/uniform/venn250.visit b/data/data/uniform/venn250.visit new file mode 100644 index 000000000..12e244a73 --- /dev/null +++ b/data/data/uniform/venn250.visit @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62accba30cde47cac6980dbec18c6edc08e48f353da8f0817a810e66631cb89e +size 38 diff --git a/vtkm/io/CMakeLists.txt b/vtkm/io/CMakeLists.txt index 1689de6b5..3aab645a5 100644 --- a/vtkm/io/CMakeLists.txt +++ b/vtkm/io/CMakeLists.txt @@ -30,6 +30,7 @@ set(headers VTKStructuredGridReader.h VTKStructuredPointsReader.h VTKUnstructuredGridReader.h + VTKVisItFileReader.h ) set(template_sources @@ -57,6 +58,7 @@ set(sources VTKStructuredGridReader.cxx VTKStructuredPointsReader.cxx VTKUnstructuredGridReader.cxx + VTKVisItFileReader.cxx ) if (VTKm_ENABLE_HDF5_IO) diff --git a/vtkm/io/VTKVisItFileReader.cxx b/vtkm/io/VTKVisItFileReader.cxx new file mode 100644 index 000000000..98e1b424c --- /dev/null +++ b/vtkm/io/VTKVisItFileReader.cxx @@ -0,0 +1,99 @@ +//============================================================================ +// 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 + +namespace vtkm +{ +namespace io +{ + +VTKVisItFileReader::VTKVisItFileReader(const char* fileName) + : FileName(fileName) +{ +} + +VTKVisItFileReader::VTKVisItFileReader(const std::string& fileName) + : FileName(fileName) +{ +} + +vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() +{ + //Get the base path of the input file. + std::string baseDirPath = "."; + baseDirPath = "../vtk-m/data/data/uniform"; + + //Get the base dir name + auto pos = this->FileName.rfind("/"); + if (pos != std::string::npos) + baseDirPath = baseDirPath.substr(0, pos); + + //Open up the file of filenames. + std::ifstream stream(this->FileName); + if (stream.fail()) + throw vtkm::io::ErrorIO("Failed to open file: " + this->FileName); + + int numBlocks = -1; + std::string line; + std::vector fileNames; + while (stream.good()) + { + std::getline(stream, line); + if (line.size() == 0 || line[0] == '#') + continue; + else if (line.find("!NBLOCKS") != std::string::npos) + { + if (numBlocks > 0) + throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + + ". Number of blocks already specified"); + numBlocks = std::atoi(line.substr(8, line.size()).c_str()); + + if (numBlocks <= 0) + throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + + ". Number of blocks must be > 0"); + } + else if (numBlocks > 0) + { + char char_to_remove = ' '; + line.erase(std::remove(line.begin(), line.end(), char_to_remove), line.end()); + if (line.find(".vtk") != std::string::npos) + fileNames.push_back(baseDirPath + "/" + line); + else + std::cerr << "Skipping: " << line << std::endl; + } + else + { + std::cerr << "Skipping line: " << line << std::endl; + } + } + + vtkm::cont::PartitionedDataSet pds; + + //Read all the files. + for (const auto fn : fileNames) + { + std::ifstream s(fn); + if (s.fail()) + throw vtkm::io::ErrorIO("Failed to open file: " + fn); + + vtkm::io::VTKDataSetReader reader(fn); + pds.AppendPartition(reader.ReadDataSet()); + } + + return pds; +} + +} +} //vtkm::io diff --git a/vtkm/io/VTKVisItFileReader.h b/vtkm/io/VTKVisItFileReader.h new file mode 100644 index 000000000..7b2495b89 --- /dev/null +++ b/vtkm/io/VTKVisItFileReader.h @@ -0,0 +1,39 @@ +//============================================================================ +// 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 vtkm_io_VTKVisItFileReader_h +#define vtkm_io_VTKVisItFileReader_h + +#include +#include +#include +#include + +namespace vtkm +{ +namespace io +{ + +class VTKM_IO_EXPORT VTKVisItFileReader +{ +public: + VTKM_CONT VTKVisItFileReader(const char* fileName); + VTKM_CONT VTKVisItFileReader(const std::string& fileName); + + VTKM_CONT vtkm::cont::PartitionedDataSet ReadPartitionedDataSet(); + +private: + std::string FileName; +}; + +} +} //vtkm::io + +#endif //vtkm_io_VTKVisItFileReader_h diff --git a/vtkm/io/testing/CMakeLists.txt b/vtkm/io/testing/CMakeLists.txt index 1ed94d1b4..de5f86107 100644 --- a/vtkm/io/testing/CMakeLists.txt +++ b/vtkm/io/testing/CMakeLists.txt @@ -10,6 +10,7 @@ set(unit_tests UnitTestBOVDataSetReader.cxx + UnitTestVisItFileDataSetReader.cxx UnitTestFileUtils.cxx UnitTestPixelTypes.cxx UnitTestVTKDataSetReader.cxx diff --git a/vtkm/io/testing/UnitTestVisItFileDataSetReader.cxx b/vtkm/io/testing/UnitTestVisItFileDataSetReader.cxx new file mode 100644 index 000000000..56362d095 --- /dev/null +++ b/vtkm/io/testing/UnitTestVisItFileDataSetReader.cxx @@ -0,0 +1,60 @@ +//============================================================================ +// 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 + +namespace +{ + +inline vtkm::cont::PartitionedDataSet readVisItFileDataSet(const std::string& fname) +{ + vtkm::cont::PartitionedDataSet pds; + vtkm::io::VTKVisItFileReader reader(fname); + try + { + pds = reader.ReadPartitionedDataSet(); + } + catch (vtkm::io::ErrorIO& e) + { + std::string message("Error reading "); + message += fname; + message += ", "; + message += e.GetMessage(); + + VTKM_TEST_FAIL(message.c_str()); + } + + return pds; +} + +} // anonymous namespace + +void TestReadingVisItFileDataSet() +{ + std::string visItFile = vtkm::cont::testing::Testing::DataPath("uniform/venn250.visit"); + + auto const& pds = readVisItFileDataSet(visItFile); + VTKM_TEST_ASSERT(pds.GetNumberOfPartitions() == 2, "Incorrect number of partitions"); + + for (const auto& ds : pds) + { + VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 63001, "Wrong number of points in partition"); + VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 5, "Wrong number of fields in partition"); + } +} + + +int UnitTestVisItFileDataSetReader(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(TestReadingVisItFileDataSet, argc, argv); +} From 2a6220726d5a692619c02ac47b7ae923a5a42eed Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Mon, 13 Mar 2023 16:26:58 -0400 Subject: [PATCH 47/64] Error checking for number of blocks. --- vtkm/io/VTKVisItFileReader.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vtkm/io/VTKVisItFileReader.cxx b/vtkm/io/VTKVisItFileReader.cxx index 98e1b424c..21c5fde95 100644 --- a/vtkm/io/VTKVisItFileReader.cxx +++ b/vtkm/io/VTKVisItFileReader.cxx @@ -33,7 +33,6 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() { //Get the base path of the input file. std::string baseDirPath = "."; - baseDirPath = "../vtk-m/data/data/uniform"; //Get the base dir name auto pos = this->FileName.rfind("/"); @@ -79,6 +78,9 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() } } + if (static_cast(numBlocks) != fileNames.size()) + throw vtkm::io::ErrorIO("Wrong number of partitions in VisIt file: " + this->FileName); + vtkm::cont::PartitionedDataSet pds; //Read all the files. From a810b08a0cc821cdcf8e8dd3b78efc7fd9065f36 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Mon, 13 Mar 2023 19:34:23 -0400 Subject: [PATCH 48/64] ci,spock,crusher: migrate build to crusher --- .gitlab-ci.yml | 4 ++-- .gitlab/ci/{spock.yml => crusher.yml} | 30 +++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) rename .gitlab/ci/{spock.yml => crusher.yml} (84%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 421d4af3a..1e6a23dd0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -96,7 +96,7 @@ when: on_success - when: never -.run_spock_ci: &run_spock_ci +.run_crusher_ci: &run_crusher_ci rules: - if: '$CI_PROJECT_PATH == "ci/csc331_crusher/dev/vtk-m"' when: on_success @@ -214,7 +214,7 @@ stages: include: - local: '/.gitlab/ci/ascent.yml' - - local: '/.gitlab/ci/spock.yml' + - local: '/.gitlab/ci/crusher.yml' - local: '/.gitlab/ci/centos7.yml' - local: '/.gitlab/ci/centos8.yml' - local: '/.gitlab/ci/doxygen.yml' diff --git a/.gitlab/ci/spock.yml b/.gitlab/ci/crusher.yml similarity index 84% rename from .gitlab/ci/spock.yml rename to .gitlab/ci/crusher.yml index 7d53c14e0..3b0b9c83f 100644 --- a/.gitlab/ci/spock.yml +++ b/.gitlab/ci/crusher.yml @@ -1,5 +1,5 @@ # Ad-hoc build that runs in the ECP Hardware, concretely in OLCF Spock. -.spock_gcc_hip: +.crusher_gcc_hip: variables: CCACHE_BASEDIR: "/gpfs/alpine/csc331/scratch/" CCACHE_DIR: "/gpfs/alpine/csc331/scratch/vbolea/ci/vtk-m/ccache" @@ -17,12 +17,12 @@ KOKKOS_OPTS: >- -DCMAKE_INSTALL_PREFIX:PATH=$CI_BUILDS_DIR/kokkos_install -DCMAKE_CXX_COMPILER:FILEPATH=/opt/rocm-4.5.0/hip/bin/hipcc - -DKokkos_ARCH_VEGA908:BOOL=ON + -DKokkos_ARCH_VEGA90A:BOOL=ON # DefApps/default;craype;rocm;gcc should be loaded first JOB_MODULES: >- DefApps/default - craype-accel-amd-gfx908 + craype-accel-amd-gfx90a rocm/4.5.0 gcc/10 cmake/3.22 @@ -30,7 +30,7 @@ git-lfs ninja zstd - VTKM_SETTINGS: kokkos+hip+gfx908+spock+ccache+no_rendering + VTKM_SETTINGS: kokkos+hip+gfx90a+crusher+ccache+no_rendering interruptible: true .setup_env_ecpci: &setup_env_ecpci | @@ -39,12 +39,12 @@ module list export PATH="${CCACHE_INSTALL_DIR}/ccache:$PATH" -build:spock_gcc_hip: +build:crusher_gcc_hip: stage: build - tags: [spock, shell, olcf-spock-shell-02] + tags: [crusher, shell] extends: - - .spock_gcc_hip - - .run_spock_ci + - .crusher_gcc_hip + - .run_crusher_ci before_script: - *setup_env_ecpci - mkdir -p "$CCACHE_INSTALL_DIR" @@ -68,18 +68,18 @@ build:spock_gcc_hip: - build/ - .gitlab/ccache/ccache -test:spock_gcc_hip: +test:crusher_gcc_hip: stage: test - tags: [spock, slurm, olcf-spock-slurm-02] + tags: [crusher, slurm] extends: - - .spock_gcc_hip - - .run_spock_ci + - .crusher_gcc_hip + - .run_crusher_ci needs: - - build:spock_gcc_hip + - build:crusher_gcc_hip dependencies: - - build:spock_gcc_hip + - build:crusher_gcc_hip variables: - SCHEDULER_PARAMETERS: "-ACSC331 -pecp -t120 --nice=0 -c32 --gpus=4 -N 1" + SCHEDULER_PARAMETERS: "-ACSC331 -pbatch -t120 --nice=0 -c32 --gpus=4 -N 1" # We need this to skip ctest_submit from being run inside a jsrun job GITLAB_CI_EMULATION: 1 # Tests errors to address due to different env in Spock From d6acc819d42e08f5777ae1d6248334103f050656 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Tue, 14 Mar 2023 11:53:56 -0400 Subject: [PATCH 49/64] ci,centos: update tag to linux-x86_64 --- .gitlab/ci/centos8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/centos8.yml b/.gitlab/ci/centos8.yml index 9f5c15edd..8775c2516 100644 --- a/.gitlab/ci/centos8.yml +++ b/.gitlab/ci/centos8.yml @@ -45,7 +45,7 @@ build:centos8: - build - vtkm - docker - - linux + - linux-x86_64 extends: - .centos8 - .cmake_build_linux From 06391c4e638f93e61a5fe04422ef788d4b39fae8 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 2 Mar 2023 10:45:27 -0700 Subject: [PATCH 50/64] Clarify license for ECL data The readme for the ECL data gave the source of the data but required a lookup for the license. Explictly give the direct link to the license and copy the license to the readme to ensure we are following the conditions of attribution. --- data/data/third_party/ecl_cc/README | 3 --- data/data/third_party/ecl_cc/README.md | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 data/data/third_party/ecl_cc/README create mode 100644 data/data/third_party/ecl_cc/README.md diff --git a/data/data/third_party/ecl_cc/README b/data/data/third_party/ecl_cc/README deleted file mode 100644 index 951012b69..000000000 --- a/data/data/third_party/ecl_cc/README +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f5e6e3dc559fefc7990daaec071fcd620f620e5ab8652dddaa6b43ca4ba08e7 -size 222 diff --git a/data/data/third_party/ecl_cc/README.md b/data/data/third_party/ecl_cc/README.md new file mode 100644 index 000000000..db4bbb6b9 --- /dev/null +++ b/data/data/third_party/ecl_cc/README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55f8b9b11031d8a200145763989dedb787efee60b24f39e0c20b139899570d96 +size 2197 From 796ec9638e8c8f7bcb37e99ba322e0cc19e1872a Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 2 Mar 2023 10:47:37 -0700 Subject: [PATCH 51/64] Document data that comes from VisIt tutorial Some of the data sets that are included from VTK-m are derived from the VisIt Tutorial Data (https://www.visitusers.org/index.php?title=Tutorial_Data). These are covered by the VisIt license, as communicated by Eric Brugger. Although the license for these data is compatible with VTK-m's license, we should still attribute the source of the data and make clear the copyrights. The data are moved into the third_party directory, and readmes are added to document everything. The noise.vtk and noise.bov files have been renamed example.vtk and example_temp.bov to match the name of the file in the VisIt tutorial data archive. The ucd3d.vtk file, which is similar to the curv3d.silo data but altered, has been removed. It was not used for any tests. It was referenced in a couple of example programs, but the reference is easily changed. --- data/baseline/rendering/volume/rectilinear3D.png | 4 ++-- data/data/rectilinear/noise.vtk | 3 --- data/data/third_party/README.md | 3 +++ data/data/third_party/visit/README.md | 3 +++ data/data/third_party/visit/example.vtk | 3 +++ .../noise => third_party/visit/example_temp.bof} | 0 data/data/third_party/visit/example_temp.bov | 3 +++ data/data/uniform/noise.bov | 3 --- data/data/unstructured/ucd3d.vtk | 3 --- examples/clipping/Clipping.cxx | 4 ++-- examples/tetrahedra/Tetrahedralize.cxx | 5 +++-- vtkm/io/testing/UnitTestBOVDataSetReader.cxx | 3 ++- vtkm/rendering/testing/UnitTestMapperVolume.cxx | 10 ++++++---- 13 files changed, 27 insertions(+), 20 deletions(-) delete mode 100644 data/data/rectilinear/noise.vtk create mode 100644 data/data/third_party/README.md create mode 100644 data/data/third_party/visit/README.md create mode 100644 data/data/third_party/visit/example.vtk rename data/data/{uniform/noise => third_party/visit/example_temp.bof} (100%) create mode 100644 data/data/third_party/visit/example_temp.bov delete mode 100644 data/data/uniform/noise.bov delete mode 100644 data/data/unstructured/ucd3d.vtk diff --git a/data/baseline/rendering/volume/rectilinear3D.png b/data/baseline/rendering/volume/rectilinear3D.png index b5889de5d..55dae9002 100644 --- a/data/baseline/rendering/volume/rectilinear3D.png +++ b/data/baseline/rendering/volume/rectilinear3D.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a24175a16a60f3e917170907546a52de15e703bd06017fecd9c6238db9d2726 -size 103177 +oid sha256:3f9bdb6825e859500308217228970c406b8f75c0ab16d0c2c8d704dfa9ae2e10 +size 116102 diff --git a/data/data/rectilinear/noise.vtk b/data/data/rectilinear/noise.vtk deleted file mode 100644 index 7f4eb0c53..000000000 --- a/data/data/rectilinear/noise.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c23821f7436bce6d71593698e3cb0047752b4dd671513f8c4e961d4489f199f -size 12110311 diff --git a/data/data/third_party/README.md b/data/data/third_party/README.md new file mode 100644 index 000000000..d59cbb591 --- /dev/null +++ b/data/data/third_party/README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:362e59e70e65fd365bc64221decdea1096ac9fe4346e23126ec2d35836215832 +size 456 diff --git a/data/data/third_party/visit/README.md b/data/data/third_party/visit/README.md new file mode 100644 index 000000000..3f9fd0a9c --- /dev/null +++ b/data/data/third_party/visit/README.md @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:279231652c3bc23c31a8c7a6bf2e71f56afd11b6e09b5c05dca5dc48380ee0fb +size 1934 diff --git a/data/data/third_party/visit/example.vtk b/data/data/third_party/visit/example.vtk new file mode 100644 index 000000000..371b6a2cd --- /dev/null +++ b/data/data/third_party/visit/example.vtk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce56bb831ac66983f9689c2a73ec0dd7a7a91294f822ad19bf1caa093a8fba25 +size 11295710 diff --git a/data/data/uniform/noise b/data/data/third_party/visit/example_temp.bof similarity index 100% rename from data/data/uniform/noise rename to data/data/third_party/visit/example_temp.bof diff --git a/data/data/third_party/visit/example_temp.bov b/data/data/third_party/visit/example_temp.bov new file mode 100644 index 000000000..3bc9a8fa9 --- /dev/null +++ b/data/data/third_party/visit/example_temp.bov @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:724a6dce8f6f5d6478891a915c76c57c5881467240bb055c6001725631f7833a +size 350 diff --git a/data/data/uniform/noise.bov b/data/data/uniform/noise.bov deleted file mode 100644 index fde60e695..000000000 --- a/data/data/uniform/noise.bov +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2071da4365341303e401d20dc6e8bb35ebeccc24b801cc81ab87e75e3a4ef654 -size 339 diff --git a/data/data/unstructured/ucd3d.vtk b/data/data/unstructured/ucd3d.vtk deleted file mode 100644 index e4ff7c88a..000000000 --- a/data/data/unstructured/ucd3d.vtk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9a178b29073f2aa0d15375b07d0bdd28369422a352b5dcb5155cf67aebe54bbc -size 286099 diff --git a/examples/clipping/Clipping.cxx b/examples/clipping/Clipping.cxx index ddae3737b..1948bcb81 100644 --- a/examples/clipping/Clipping.cxx +++ b/examples/clipping/Clipping.cxx @@ -24,9 +24,9 @@ int main(int argc, char* argv[]) if ((argc < 4) || (argc > 5)) { std::cerr << "Usage: " << argv[0] << " in_data.vtk field_name clip_value [out_data.vtk]\n\n"; - std::cerr << "For example, you could use the ucd3d.vtk that comes with the VTK-m source:\n\n"; + std::cerr << "For example, you could use the example.vtk that comes with the VTK-m source:\n\n"; std::cerr << " " << argv[0] - << " /data/data/unstructured/ucd3d.vtk v 0.3\n"; + << " /data/data/third_party/visit/example.vtk temp 3.5\n"; return 1; } std::string infilename = argv[1]; diff --git a/examples/tetrahedra/Tetrahedralize.cxx b/examples/tetrahedra/Tetrahedralize.cxx index 0734565a3..e8e98fda8 100644 --- a/examples/tetrahedra/Tetrahedralize.cxx +++ b/examples/tetrahedra/Tetrahedralize.cxx @@ -24,8 +24,9 @@ int main(int argc, char* argv[]) if ((argc < 2) || (argc > 3)) { std::cerr << "Usage: " << argv[0] << " in_data.vtk [out_data.vtk]\n\n"; - std::cerr << "For example, you could use the ucd3d.vtk that comes with the VTK-m source:\n\n"; - std::cerr << " " << argv[0] << " /data/data/unstructured/ucd3d.vtk\n"; + std::cerr << "For example, you could use the example.vtk that comes with the VTK-m source:\n\n"; + std::cerr << " " << argv[0] + << " /data/data/third_party/visit/example.vtk\n"; return 1; } std::string infilename = argv[1]; diff --git a/vtkm/io/testing/UnitTestBOVDataSetReader.cxx b/vtkm/io/testing/UnitTestBOVDataSetReader.cxx index 606acd2de..46dec8eff 100644 --- a/vtkm/io/testing/UnitTestBOVDataSetReader.cxx +++ b/vtkm/io/testing/UnitTestBOVDataSetReader.cxx @@ -41,7 +41,8 @@ inline vtkm::cont::DataSet readBOVDataSet(const char* fname) void TestReadingBOVDataSet() { - std::string bovFile = vtkm::cont::testing::Testing::DataPath("uniform/noise.bov"); + std::string bovFile = + vtkm::cont::testing::Testing::DataPath("third_party/visit/example_temp.bov"); auto const& ds = readBOVDataSet(bovFile.data()); diff --git a/vtkm/rendering/testing/UnitTestMapperVolume.cxx b/vtkm/rendering/testing/UnitTestMapperVolume.cxx index d2058a6cc..c18dac035 100644 --- a/vtkm/rendering/testing/UnitTestMapperVolume.cxx +++ b/vtkm/rendering/testing/UnitTestMapperVolume.cxx @@ -26,8 +26,10 @@ namespace void RenderTests() { vtkm::cont::ColorTable colorTable = vtkm::cont::ColorTable::Preset::Inferno; - colorTable.AddPointAlpha(0.0, .01f); - colorTable.AddPointAlpha(1.0, .01f); + colorTable.AddPointAlpha(0.0, 0.01f); + colorTable.AddPointAlpha(0.4, 0.01f); + colorTable.AddPointAlpha(0.7, 0.2f); + colorTable.AddPointAlpha(1.0, 0.5f); vtkm::rendering::testing::RenderTestOptions options; options.Mapper = vtkm::rendering::testing::MapperType::Volume; @@ -35,7 +37,7 @@ void RenderTests() options.ColorTable = colorTable; vtkm::cont::DataSet rectDS, unsDS; - std::string rectfname = vtkm::cont::testing::Testing::DataPath("rectilinear/noise.vtk"); + std::string rectfname = vtkm::cont::testing::Testing::DataPath("third_party/visit/example.vtk"); vtkm::io::VTKDataSetReader rectReader(rectfname); try @@ -53,7 +55,7 @@ void RenderTests() } vtkm::rendering::testing::RenderTest( - rectDS, "hardyglobal", "rendering/volume/rectilinear3D.png", options); + rectDS, "temp", "rendering/volume/rectilinear3D.png", options); } } //namespace From 60559ce9b10a408d6359e73cdb83345fde0ec229 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Fri, 3 Mar 2023 13:04:16 -0700 Subject: [PATCH 52/64] Document the source of venn250.vtk The venn250.vtk file was generated by running one of the Blueprint examples. The library function used to generate the data is documented here: https://llnl-conduit.readthedocs.io/en/latest/blueprint_mesh.html#venn --- data/data/uniform/venn250.vtk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/data/uniform/venn250.vtk b/data/data/uniform/venn250.vtk index 83eca4028..f4027f6a8 100644 --- a/data/data/uniform/venn250.vtk +++ b/data/data/uniform/venn250.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d68d7acc1199af1de37ff581c6e39309e99dc0bae977fc9a0abf054d80aeb52a -size 2004559 +oid sha256:553468d1130df26b48823fa5dc0f58196920056106b9bf0d312d651c66e423c5 +size 2004653 From a24358a1a3d5723b409ad95ff84893f5e1979a76 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 8 Mar 2023 08:35:48 -0700 Subject: [PATCH 53/64] Document source of WarpX files These files come courtesy of Axel Huebl (LBNL). They are simple outputs from the WarpX code. --- data/data/misc/warpXfields.vtk | 4 ++-- data/data/misc/warpXparticles.vtk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/data/misc/warpXfields.vtk b/data/data/misc/warpXfields.vtk index 90bbbda86..faf91ccf5 100644 --- a/data/data/misc/warpXfields.vtk +++ b/data/data/misc/warpXfields.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a569aff0c6872611ef75a4dcb597e1320cb966b80f840a0dbd76a29b2760dbb -size 50335052 +oid sha256:347b03839fde1734ce4bd7bbf660524d039246ca3a7fd54c356a5fd7d1ffccf8 +size 50335089 diff --git a/data/data/misc/warpXparticles.vtk b/data/data/misc/warpXparticles.vtk index 14b0ff0d8..4d054c0a3 100644 --- a/data/data/misc/warpXparticles.vtk +++ b/data/data/misc/warpXparticles.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:671345bdb045aeadc8e9fa1060de51e53286c74929c6c8c60a529b318f02bbfc -size 3795 +oid sha256:9ab17ce444d6df1ab28f24ea997adaf2a406ca6b5035da6b17867f742380fbf4 +size 3832 From f545feba8f46b4bb27c535a22ea88b060440b79a Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 14 Mar 2023 12:22:37 -0600 Subject: [PATCH 54/64] Add changelog for documenting data license --- docs/changelog/data-license.md | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/changelog/data-license.md diff --git a/docs/changelog/data-license.md b/docs/changelog/data-license.md new file mode 100644 index 000000000..54cf1c308 --- /dev/null +++ b/docs/changelog/data-license.md @@ -0,0 +1,44 @@ +# Clarified license of test data + +The VTK-m source comes distributed with several data files used for +regression testing. Some of these are generated specifically by VTK-m +developers and are released as part of the VTK-m license, but some come +from external sources. For those that come from external sources, we have +clarified the license and attribution of those files. In particular, the +following files originate from external sources. + +* **internet.egr**: Distributed as part of a graph data set paper. The + license of this data is compatible with VTK-m's license. The file is + placed in the third-party data directory and the information has been + updated to clearly document the correct license for this data. +* **example.vtk** and **example_temp.bov**: Distributed as part of the + VisIt tutorials. This data is provided under the VisIt license (per Eric + Brugger), which is compatible with VTK-m's license. The files are moved + to the third-party data directory and the license and attribution is + clarified. (These files were previously named "noise" but were changed to + match the VisIt tutorial files they came from.) +* **vanc.vtk** Data derived from a digital elevation map of Vancouver that + comes from GTOPO30. This data is in the public domain, so it is valid for + us to use, modify, and redistribute the data under our license. + +The fishtank and fusion/magField datasets were removed. These are standard +flow testing data sets that are commonly distributed. However, we could not +track down the original source and license, so to be cautious these data +sets have been removed and replaced with some generated in house. + +For some of the other data sets, we have traced down the original author +and verified that they propery contribute the data to VTK-m and agree to +allow it to be distributed under VTK-m's license. Not counting the most +trivial examples, here are the originators of the non-trivial data +examples. + +* **5x6_&_MC*.ctm** and **8x9test_HierarchicalAugmentedTree*.dat**: Hamish + Carr +* **warpXfields.vtk** and **warpXparticles.vtk**: Axel Huebl +* **amr_wind_flowfield.vtk**: James Kress +* **DoubleGyre*.vtk**: James Kress +* **venn250.vtk**: Abhishek Yenpure +* **wedge_cells.vtk**: Chris Laganella +* **kitchen.vtk**: Copyright owned by Kitware, Inc. (who shares the + copyright of VTK-m) + From c98955011188ca43f940dcada1c23eca5aaed757 Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Tue, 14 Mar 2023 15:15:06 -0400 Subject: [PATCH 55/64] Better error checking and logging. --- vtkm/io/VTKVisItFileReader.cxx | 26 ++++++++++++++++++-------- vtkm/io/VTKVisItFileReader.h | 13 +++++++++++++ vtkm/io/testing/CMakeLists.txt | 2 +- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/vtkm/io/VTKVisItFileReader.cxx b/vtkm/io/VTKVisItFileReader.cxx index 21c5fde95..66de8e22a 100644 --- a/vtkm/io/VTKVisItFileReader.cxx +++ b/vtkm/io/VTKVisItFileReader.cxx @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -52,13 +53,14 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() std::getline(stream, line); if (line.size() == 0 || line[0] == '#') continue; - else if (line.find("!NBLOCKS") != std::string::npos) + else if (line.rfind("!NBLOCKS", 0) != std::string::npos) { + //!NBLOCKS is already set!! if (numBlocks > 0) throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + ". Number of blocks already specified"); - numBlocks = std::atoi(line.substr(8, line.size()).c_str()); + numBlocks = std::atoi(line.substr(8, line.size()).c_str()); if (numBlocks <= 0) throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + ". Number of blocks must be > 0"); @@ -68,16 +70,28 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() char char_to_remove = ' '; line.erase(std::remove(line.begin(), line.end(), char_to_remove), line.end()); if (line.find(".vtk") != std::string::npos) + { fileNames.push_back(baseDirPath + "/" + line); + } else - std::cerr << "Skipping: " << line << std::endl; + { + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + "Skipping: " << line << ". It does not appear to be a legacy VTK file."); + continue; + } } else { - std::cerr << "Skipping line: " << line << std::endl; + VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Skipping line: " << line); + continue; } } + if (numBlocks < 0) + { + throw vtkm::io::ErrorIO("`!NBLOCKS` line not provided in VisIt file: " + this->FileName); + } + if (static_cast(numBlocks) != fileNames.size()) throw vtkm::io::ErrorIO("Wrong number of partitions in VisIt file: " + this->FileName); @@ -86,10 +100,6 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() //Read all the files. for (const auto fn : fileNames) { - std::ifstream s(fn); - if (s.fail()) - throw vtkm::io::ErrorIO("Failed to open file: " + fn); - vtkm::io::VTKDataSetReader reader(fn); pds.AppendPartition(reader.ReadDataSet()); } diff --git a/vtkm/io/VTKVisItFileReader.h b/vtkm/io/VTKVisItFileReader.h index 7b2495b89..704eb76f5 100644 --- a/vtkm/io/VTKVisItFileReader.h +++ b/vtkm/io/VTKVisItFileReader.h @@ -21,6 +21,19 @@ namespace vtkm namespace io { +// Reader for ".visit" files, a simple file format for partioned data sets. +// The file format consists of the keyword "!NBLOCKS ", where N is the number of +// partitions, followed by a list of the N files. For example: +// +/* +!NBLOCKS 2 +file1.vtk +file2.vtk +*/ +// +// Note: .visit files support time varying partitione data, but it is not supported +// in this reader. + class VTKM_IO_EXPORT VTKVisItFileReader { public: diff --git a/vtkm/io/testing/CMakeLists.txt b/vtkm/io/testing/CMakeLists.txt index de5f86107..e23696add 100644 --- a/vtkm/io/testing/CMakeLists.txt +++ b/vtkm/io/testing/CMakeLists.txt @@ -10,9 +10,9 @@ set(unit_tests UnitTestBOVDataSetReader.cxx - UnitTestVisItFileDataSetReader.cxx UnitTestFileUtils.cxx UnitTestPixelTypes.cxx + UnitTestVisItFileDataSetReader.cxx UnitTestVTKDataSetReader.cxx UnitTestVTKDataSetWriter.cxx ) From 39cb7a653b167cfe4aa8ce7ea758ffb39f19f292 Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Tue, 14 Mar 2023 21:06:02 -0400 Subject: [PATCH 56/64] kick the build machines. --- vtkm/io/VTKVisItFileReader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vtkm/io/VTKVisItFileReader.h b/vtkm/io/VTKVisItFileReader.h index 704eb76f5..718ac41d0 100644 --- a/vtkm/io/VTKVisItFileReader.h +++ b/vtkm/io/VTKVisItFileReader.h @@ -21,6 +21,7 @@ namespace vtkm namespace io { +// // Reader for ".visit" files, a simple file format for partioned data sets. // The file format consists of the keyword "!NBLOCKS ", where N is the number of // partitions, followed by a list of the N files. For example: From 97b460110fe5246da7108cb66cb776464c1cb163 Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Wed, 15 Mar 2023 12:45:45 -0400 Subject: [PATCH 57/64] Fix issues....... --- vtkm/io/VTKVisItFileReader.cxx | 11 ++++++----- vtkm/io/VTKVisItFileReader.h | 27 ++++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/vtkm/io/VTKVisItFileReader.cxx b/vtkm/io/VTKVisItFileReader.cxx index 66de8e22a..513576787 100644 --- a/vtkm/io/VTKVisItFileReader.cxx +++ b/vtkm/io/VTKVisItFileReader.cxx @@ -38,7 +38,7 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() //Get the base dir name auto pos = this->FileName.rfind("/"); if (pos != std::string::npos) - baseDirPath = baseDirPath.substr(0, pos); + baseDirPath = this->FileName.substr(0, pos); //Open up the file of filenames. std::ifstream stream(this->FileName); @@ -58,12 +58,12 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() //!NBLOCKS is already set!! if (numBlocks > 0) throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + - ". Number of blocks already specified"); + ". `!NBLOCKS` specified more than once."); numBlocks = std::atoi(line.substr(8, line.size()).c_str()); if (numBlocks <= 0) throw vtkm::io::ErrorIO("Invalid file: " + this->FileName + - ". Number of blocks must be > 0"); + ". Number of blocks (!NBLOCKS) must be > 0."); } else if (numBlocks > 0) { @@ -82,7 +82,8 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() } else { - VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Skipping line: " << line); + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + "Skipping line that occurs before `!NBLOCKS`: " << line); continue; } } @@ -98,7 +99,7 @@ vtkm::cont::PartitionedDataSet VTKVisItFileReader::ReadPartitionedDataSet() vtkm::cont::PartitionedDataSet pds; //Read all the files. - for (const auto fn : fileNames) + for (auto&& fn : fileNames) { vtkm::io::VTKDataSetReader reader(fn); pds.AppendPartition(reader.ReadDataSet()); diff --git a/vtkm/io/VTKVisItFileReader.h b/vtkm/io/VTKVisItFileReader.h index 718ac41d0..caed9e9e9 100644 --- a/vtkm/io/VTKVisItFileReader.h +++ b/vtkm/io/VTKVisItFileReader.h @@ -21,19 +21,20 @@ namespace vtkm namespace io { -// -// Reader for ".visit" files, a simple file format for partioned data sets. -// The file format consists of the keyword "!NBLOCKS ", where N is the number of -// partitions, followed by a list of the N files. For example: -// -/* -!NBLOCKS 2 -file1.vtk -file2.vtk -*/ -// -// Note: .visit files support time varying partitione data, but it is not supported -// in this reader. +/// Reader for ".visit" files, a simple file format for partioned data sets. +/// The file format consists of the keyword "!NBLOCKS ", where N is the number of +/// partitions, followed by a list of the N files. For example: +/// +/// ``` +/// # This is a comment +/// !NBLOCKS 2 +/// file1.vtk +/// file2.vtk +/// ``` +/// +/// Note: .visit files support time varying partitioned data, but it is not supported +/// in this reader. +/// class VTKM_IO_EXPORT VTKVisItFileReader { From ac889b500462eecc671ff2b82f52c8d1be304deb Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 16 Mar 2023 11:00:47 -0600 Subject: [PATCH 58/64] Implement VecTraits class for all types The `VecTraits` class allows templated functions, methods, and classes to treat type arguments uniformly as `Vec` types or to otherwise differentiate between scalar and vector types. This only works for types that `VecTraits` is defined for. The `VecTraits` templated class now has a default implementation that will be used for any type that does not have a `VecTraits` specialization. This removes many surprise compiler errors when using a template that, unknown to you, has `VecTraits` in its implementation. One potential issue is that if `VecTraits` gets defined for a new type, the behavior of `VecTraits` could change for that type in backward-incompatible ways. If `VecTraits` is used in a purely generic way, this should not be an issue. However, if assumptions were made about the components and length, this could cause problems. Fixes #589 --- docs/changelog/vectraits-for-all.md | 19 ++ vtkm/TypeTraits.h | 2 +- vtkm/VecFlat.h | 22 +- vtkm/VecFromPortal.h | 3 +- vtkm/VecTraits.h | 310 +++++++++--------- vtkm/cont/ArrayCopy.h | 20 -- vtkm/cont/ArrayExtractComponent.h | 38 +-- vtkm/cont/ArrayGetValues.h | 3 - vtkm/cont/ArrayHandle.h | 10 +- vtkm/cont/ArrayHandleCounting.h | 20 +- vtkm/cont/ArrayHandleRecombineVec.h | 22 +- vtkm/cont/ArrayHandleRuntimeVec.h | 2 +- vtkm/cont/ArrayHandleSOA.h | 1 - vtkm/cont/UnknownArrayHandle.h | 22 +- vtkm/cont/internal/MapArrayPermutation.cxx | 1 - .../testing/UnitTestArrayHandleRuntimeVec.cxx | 4 +- vtkm/internal/ArrayPortalValueReference.h | 41 +-- vtkm/io/internal/VTKDataSetTypes.h | 4 +- vtkm/testing/Testing.h | 18 +- vtkm/testing/UnitTestVecTraits.cxx | 22 +- vtkm/testing/VecTraitsTests.h | 40 ++- 21 files changed, 291 insertions(+), 333 deletions(-) create mode 100644 docs/changelog/vectraits-for-all.md diff --git a/docs/changelog/vectraits-for-all.md b/docs/changelog/vectraits-for-all.md new file mode 100644 index 000000000..9de668741 --- /dev/null +++ b/docs/changelog/vectraits-for-all.md @@ -0,0 +1,19 @@ +# Implemented `VecTraits` class for all types + +The `VecTraits` class allows templated functions, methods, and classes to +treat type arguments uniformly as `Vec` types or to otherwise differentiate +between scalar and vector types. This only works for types that `VecTraits` +is defined for. + +The `VecTraits` templated class now has a default implementation that will +be used for any type that does not have a `VecTraits` specialization. This +removes many surprise compiler errors when using a template that, unknown +to you, has `VecTraits` in its implementation. + +One potential issue is that if `VecTraits` gets defined for a new type, the +behavior of `VecTraits` could change for that type in backward-incompatible +ways. If `VecTraits` is used in a purely generic way, this should not be an +issue. However, if assumptions were made about the components and length, +this could cause problems. + +Fixes #589. diff --git a/vtkm/TypeTraits.h b/vtkm/TypeTraits.h index f321d3bf9..ae1a5e7ca 100644 --- a/vtkm/TypeTraits.h +++ b/vtkm/TypeTraits.h @@ -69,7 +69,7 @@ public: /// \brief A tag to determine whether the type has multiple components. /// /// This tag is either TypeTraitsScalarTag or TypeTraitsVectorTag. Scalars can - /// also be treated as vectors. + /// also be treated as vectors with VecTraits. using DimensionalityTag = vtkm::TypeTraitsUnknownTag; VTKM_EXEC_CONT static T ZeroInitialization() { return T(); } diff --git a/vtkm/VecFlat.h b/vtkm/VecFlat.h index 476241881..01d2b5028 100644 --- a/vtkm/VecFlat.h +++ b/vtkm/VecFlat.h @@ -22,20 +22,18 @@ namespace internal { template ::HasMultipleComponents> + typename MultipleComponents = typename vtkm::VecTraits::HasMultipleComponents> struct TotalNumComponents; template struct TotalNumComponents { VTKM_STATIC_ASSERT_MSG( - (std::is_same::IsSizeStatic, - vtkm::VecTraitsTagSizeStatic>::value), + (std::is_same::IsSizeStatic, vtkm::VecTraitsTagSizeStatic>::value), "vtkm::VecFlat can only be used with Vec types with a static number of components."); - using ComponentType = typename vtkm::internal::SafeVecTraits::ComponentType; + using ComponentType = typename vtkm::VecTraits::ComponentType; static constexpr vtkm::IdComponent value = - vtkm::internal::SafeVecTraits::NUM_COMPONENTS * TotalNumComponents::value; + vtkm::VecTraits::NUM_COMPONENTS * TotalNumComponents::value; }; template @@ -45,7 +43,7 @@ struct TotalNumComponents }; template -using FlattenVec = vtkm::Vec::BaseComponentType, +using FlattenVec = vtkm::Vec::BaseComponentType, vtkm::internal::TotalNumComponents::value>; template @@ -64,10 +62,10 @@ VTKM_EXEC_CONT T GetFlatVecComponentImpl(const T& component, } template -VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType +VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type vtkmNotUsed(isBase)) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; using BaseComponentType = typename Traits::BaseComponentType; @@ -80,7 +78,7 @@ GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type v } // namespace detail template -VTKM_EXEC_CONT typename vtkm::internal::SafeVecTraits::BaseComponentType GetFlatVecComponent( +VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponent( const T& vec, vtkm::IdComponent index) { @@ -114,7 +112,7 @@ VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(const NestedVecType& nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; @@ -176,7 +174,7 @@ VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, NestedVecType& nestedVec) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; diff --git a/vtkm/VecFromPortal.h b/vtkm/VecFromPortal.h index a5b5caca2..4f2330981 100644 --- a/vtkm/VecFromPortal.h +++ b/vtkm/VecFromPortal.h @@ -117,8 +117,7 @@ struct VecTraits> using VecType = vtkm::VecFromPortal; using ComponentType = typename VecType::ComponentType; - using BaseComponentType = - typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents; using IsSizeStatic = vtkm::VecTraitsTagSizeVariable; diff --git a/vtkm/VecTraits.h b/vtkm/VecTraits.h index 440a4ced2..a66ad5136 100644 --- a/vtkm/VecTraits.h +++ b/vtkm/VecTraits.h @@ -10,6 +10,8 @@ #ifndef vtk_m_VecTraits_h #define vtk_m_VecTraits_h +#include +#include #include namespace vtkm @@ -42,64 +44,55 @@ struct VecTraitsTagSizeVariable { }; -namespace internal -{ - -// Forward declaration -template -struct SafeVecTraits; - -template -struct VecTraitsMultipleComponentChooser -{ - using Type = vtkm::VecTraitsTagMultipleComponents; -}; - -template -struct VecTraitsMultipleComponentChooser<1, ComponentType> -{ - using Type = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; -}; - -} // namespace internal - -/// The VecTraits class gives several static members that define how -/// to use a given type as a vector. +/// \brief Traits that can be queried to treat any type as a `Vec`. /// -template +/// The VecTraits class gives several static members that define how +/// to use a given type as a vector. This is useful for templated +/// functions and methods that have a parameter that could be either +/// a standard scalar type or a `Vec` or some other `Vec`-like +/// object. When using this class, scalar objects are treated like +/// a `Vec` of size 1. +/// +/// The default implementation of this template treats the type as +/// a scalar. Types that actually behave like vectors should +/// specialize this template to provide the proper information. +/// +template struct VTKM_NEVER_EXPORT VecTraits { -#ifdef VTKM_DOXYGEN_ONLY + // The base VecTraits should not be used with qualifiers. + VTKM_STATIC_ASSERT_MSG((std::is_same>, T>::value), + "The base VecTraits should not be used with qualifiers."); + /// \brief Type of the components in the vector. /// /// If the type is really a scalar, then the component type is the same as the scalar type. /// - using ComponentType = typename VecType::ComponentType; + using ComponentType = T; /// \brief Base component type in the vector. /// /// Similar to ComponentType except that for nested vectors (e.g. Vec, N>), it /// returns the base scalar type at the end of the composition (T in this example). /// - using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; + using BaseComponentType = T; /// \brief Number of components in the vector. /// /// This is only defined for vectors of a static size. /// - static constexpr vtkm::IdComponent NUM_COMPONENTS = VecType::NUM_COMPONENTS; + static constexpr vtkm::IdComponent NUM_COMPONENTS = 1; /// Number of components in the given vector. /// - static vtkm::IdComponent GetNumberOfComponents(const VecType& vec); + static constexpr vtkm::IdComponent GetNumberOfComponents(const T&) { return NUM_COMPONENTS; } /// \brief A tag specifying whether this vector has multiple components (i.e. is a "real" vector). /// /// This tag can be useful for creating specialized functions when a vector /// is really just a scalar. /// - using HasMultipleComponents = - typename internal::VecTraitsMultipleComponentChooser::Type; + using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent; /// \brief A tag specifying whether the size of this vector is known at compile time. /// @@ -111,81 +104,113 @@ struct VTKM_NEVER_EXPORT VecTraits /// Returns the value in a given component of the vector. /// - VTKM_EXEC_CONT static const ComponentType& GetComponent( - const typename std::remove_const::type& vector, - vtkm::IdComponent component); - VTKM_EXEC_CONT static ComponentType& GetComponent( - typename std::remove_const::type& vector, - vtkm::IdComponent component); + VTKM_EXEC_CONT static const ComponentType& GetComponent(const T& vector, + vtkm::IdComponent vtkmNotUsed(component)) + { + return vector; + } + VTKM_EXEC_CONT static ComponentType& GetComponent(T& vector, + vtkm::IdComponent vtkmNotUsed(component)) + { + return vector; + } /// Changes the value in a given component of the vector. /// - VTKM_EXEC_CONT static void SetComponent(VecType& vector, - vtkm::IdComponent component, - ComponentType value); + VTKM_EXEC_CONT static void SetComponent(T& vector, + vtkm::IdComponent vtkmNotUsed(component), + ComponentType value) + { + vector = value; + } /// \brief Get a vector of the same type but with a different component. /// /// This type resolves to another vector with a different component type. For example, - /// @code vtkm::VecTraits>::ReplaceComponentType @endcode is vtkm::Vec. - /// This replacement is not recursive. So @code VecTraits, N>::ReplaceComponentType @endcode - /// is vtkm::Vec. + /// `vtkm::VecTraits>::ReplaceComponentType` is `vtkm::Vec`. + /// This replacement is not recursive. So `VecTraits, N>::ReplaceComponentType` + /// is `vtkm::Vec`. /// template - using ReplaceComponentType = VecTemplate; + using ReplaceComponentType = NewComponentType; /// \brief Get a vector of the same type but with a different base component. /// /// This type resolves to another vector with a different base component type. The replacement /// is recursive for nested types. For example, - /// @code VecTraits, N>::ReplaceBaseComponentType @endcode is Vec, N>. + /// `VecTraits, N>::ReplaceBaseComponentType` is `Vec, N>`. /// template - using ReplaceBaseComponentType = VecTemplate< - typename VecTraits::template ReplaceBaseComponentType, - N>; + using ReplaceBaseComponentType = NewComponentType; /// Copies the components in the given vector into a given Vec object. /// - template - VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec& dest); -#endif // VTKM_DOXYGEN_ONLY + template + VTKM_EXEC_CONT static void CopyInto(const T& src, vtkm::Vec& dest) + { + dest[0] = src; + } }; -namespace detail -{ - template -struct HasVecTraitsImpl -{ - template ::ComponentType> - static std::true_type Test(A*); +using HasVecTraits VTKM_DEPRECATED(2.1, "All types now have VecTraits defined.") = std::true_type; - static std::false_type Test(...); - - using Type = decltype(Test(std::declval())); -}; - -} // namespace detail - -/// \brief Determines whether the given type has VecTraits defined. -/// -/// If the given type T has a valid VecTraits class, then HasVecTraits will be set to -/// std::true_type. Otherwise it will be set to std::false_type. For example, -/// HasVecTraits is the same as std::true_type whereas HasVecTraits is the same -/// as std::false_type. This is useful to block the definition of methods using VecTraits when -/// VecTraits are not defined. -/// -template -using HasVecTraits = typename detail::HasVecTraitsImpl::Type; - -// This partial specialization allows you to define a non-const version of -// VecTraits and have it still work for const version. -// +// These partial specializations allow VecTraits to work with const and reference qualifiers. template struct VTKM_NEVER_EXPORT VecTraits : VecTraits { }; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; + +// This partial specialization allows VecTraits to work with pointers. +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ + VTKM_EXEC_CONT static vtkm::IdComponent GetNumberOfComponents(const T* vector) + { + return VecTraits::GetNumberOfComponents(*vector); + } + VTKM_EXEC_CONT static auto GetComponent(const T* vector, vtkm::IdComponent component) + -> decltype(VecTraits::GetComponent(*vector, component)) + { + return VecTraits::GetComponent(*vector, component); + } + VTKM_EXEC_CONT static auto GetComponent(T* vector, vtkm::IdComponent component) + -> decltype(VecTraits::GetComponent(*vector, component)) + { + return VecTraits::GetComponent(*vector, component); + } + VTKM_EXEC_CONT static void SetComponent(T* vector, + vtkm::IdComponent component, + typename VecTraits::ComponentType value) + { + VecTraits::SetComponent(*vector, component, value); + } + template + using ReplaceComponentType = + typename VecTraits::template ReplaceComponentType*; + template + using ReplaceBaseComponentType = + typename VecTraits::template ReplaceBaseComponentType*; + template + VTKM_EXEC_CONT static void CopyInto( + const T* src, + vtkm::Vec::ComponentType, destSize>& dest) + { + VecTraits::CopyInto(*src, dest); + } +}; +template +struct VTKM_NEVER_EXPORT VecTraits : VecTraits +{ +}; #if defined(VTKM_GCC) && (__GNUC__ <= 5) namespace detail @@ -201,13 +226,29 @@ template struct VecReplaceBaseComponentTypeGCC4or5 { using type = - vtkm::Vec::template ReplaceBaseComponentType, - Size>; + vtkm::Vec::template ReplaceBaseComponentType, Size>; }; } // namespace detail #endif // GCC Version 4.8 +namespace internal +{ + +template +struct VecTraitsMultipleComponentChooser +{ + using Type = vtkm::VecTraitsTagMultipleComponents; +}; + +template +struct VecTraitsMultipleComponentChooser<1, ComponentType> +{ + using Type = typename vtkm::VecTraits::HasMultipleComponents; +}; + +} // namespace internal + template struct VTKM_NEVER_EXPORT VecTraits> { @@ -224,8 +265,7 @@ struct VTKM_NEVER_EXPORT VecTraits> /// Similar to ComponentType except that for nested vectors (e.g. Vec, N>), it /// returns the base scalar type at the end of the composition (T in this example). /// - using BaseComponentType = - typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; /// Number of components in the vector. /// @@ -304,10 +344,9 @@ struct VTKM_NEVER_EXPORT VecTraits> typename detail::VecReplaceBaseComponentTypeGCC4or5::type; #else // !GCC <= 5 template - using ReplaceBaseComponentType = - vtkm::Vec::template ReplaceBaseComponentType, - Size>; + using ReplaceBaseComponentType = vtkm::Vec< + typename vtkm::VecTraits::template ReplaceBaseComponentType, + Size>; #endif ///@} @@ -509,7 +548,8 @@ namespace internal /// Used for overriding VecTraits for basic scalar types. /// template -struct VTKM_NEVER_EXPORT VecTraitsBasic +struct VTKM_DEPRECATED(2.1, "VecTraitsBasic is now the default implementation for VecTraits.") + VTKM_NEVER_EXPORT VecTraitsBasic { using ComponentType = ScalarType; using BaseComponentType = ScalarType; @@ -548,87 +588,41 @@ struct VTKM_NEVER_EXPORT VecTraitsBasic } }; -namespace detail -{ - -template > -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl; - template -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl : vtkm::VecTraits -{ -}; - -template -struct VTKM_NEVER_EXPORT SafeVecTraitsImpl : vtkm::internal::VecTraitsBasic -{ -}; - -} // namespace detail - -/// \brief A version of VecTraits that will be available for any type. -/// -/// The `VecTraits` template is only defined for types that have a specific specialization -/// for it. That means if you use `VecTraits` in a template, that template will likely -/// fail to build for types that are not defined for `VecTraits`. -/// -/// To use `VecTraits` in a class that should support all types, not just those with -/// defined `VecTraits`, you can use this "safe" version. `SafeVecTraits` is the same as -/// `VecTraits` if the latter is defined. If the `VecTraits` are not defined, then -/// `SafeVecTraits` treats the type as a simple scalar value. -/// -/// This template ensures that it will work reasonably well for all types. But be careful -/// as if `VecTraits` is later defined, the template is likely to change. -/// -template -struct VTKM_NEVER_EXPORT SafeVecTraits : detail::SafeVecTraitsImpl +struct VTKM_DEPRECATED(2.1 "VecTraits now safe to use on any type.") VTKM_NEVER_EXPORT SafeVecTraits + : vtkm::VecTraits { }; } // namespace internal -/// \brief VecTraits for Pair types -/// -/// Although a pair would seem better as a size-2 vector, we treat it as a -/// scalar. This is because a \c Vec is assumed to have the same type for -/// every component, and a pair in general has a different type for each -/// component. Thus we treat a pair as a "scalar" unit. -/// -template -struct VTKM_NEVER_EXPORT VecTraits> - : public vtkm::internal::VecTraitsBasic> +namespace detail +{ + +struct VTKM_DEPRECATED(2.1, + "VTKM_BASIC_TYPE_VECTOR is no longer necessary because VecTraits implements " + "basic type by default.") VTKM_BASIC_TYPE_VECTOR_is_deprecated { }; +template +struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning; + +} + } // namespace vtkm -#define VTKM_BASIC_TYPE_VECTOR(type) \ - namespace vtkm \ - { \ - template <> \ - struct VTKM_NEVER_EXPORT VecTraits : public vtkm::internal::VecTraitsBasic \ - { \ - }; \ +#define VTKM_BASIC_TYPE_VECTOR(type) \ + namespace vtkm \ + { \ + namespace detail \ + { \ + template <> \ + struct issue_VTKM_BASIC_TYPE_VECTOR_deprecation_warning \ + : public vtkm::detail::VTKM_BASIC_TYPE_VECTOR_is_deprecated \ + { \ + }; \ + } \ } -/// Allows you to treat basic types as if they were vectors. - -VTKM_BASIC_TYPE_VECTOR(float) -VTKM_BASIC_TYPE_VECTOR(double) - -VTKM_BASIC_TYPE_VECTOR(bool) -VTKM_BASIC_TYPE_VECTOR(char) -VTKM_BASIC_TYPE_VECTOR(signed char) -VTKM_BASIC_TYPE_VECTOR(unsigned char) -VTKM_BASIC_TYPE_VECTOR(short) -VTKM_BASIC_TYPE_VECTOR(unsigned short) -VTKM_BASIC_TYPE_VECTOR(int) -VTKM_BASIC_TYPE_VECTOR(unsigned int) -VTKM_BASIC_TYPE_VECTOR(long) -VTKM_BASIC_TYPE_VECTOR(unsigned long) -VTKM_BASIC_TYPE_VECTOR(long long) -VTKM_BASIC_TYPE_VECTOR(unsigned long long) - -//#undef VTKM_BASIC_TYPE_VECTOR - #endif //vtk_m_VecTraits_h diff --git a/vtkm/cont/ArrayCopy.h b/vtkm/cont/ArrayCopy.h index 612a7e4f4..8e70f1c1e 100644 --- a/vtkm/cont/ArrayCopy.h +++ b/vtkm/cont/ArrayCopy.h @@ -33,21 +33,6 @@ namespace cont namespace detail { -// Compile-time check to make sure that an `ArrayHandle` passed to `ArrayCopy` -// can be passed to a `UnknownArrayHandle`. This function does nothing -// except provide a compile error that is easier to understand than if you -// let it go and error in `UnknownArrayHandle`. (Huh? I'm not using that.) -template -inline void ArrayCopyValueTypeCheck() -{ - VTKM_STATIC_ASSERT_MSG(vtkm::HasVecTraits::value, - "An `ArrayHandle` that has a special value type that is not supported " - "by the precompiled version of `ArrayCopy` has been used. If this array " - "must be deep copied, consider using `ArrayCopyDevice`. Look at the " - "compile error for the type assigned to template parameter `T` to " - "see the offending type."); -} - template struct ArrayCopyConcreteSrc; @@ -74,8 +59,6 @@ void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source, std::false_type, std::true_type) { - detail::ArrayCopyValueTypeCheck(); - using DestType = vtkm::cont::ArrayHandle; if (source.CanConvert()) { @@ -96,9 +79,6 @@ void ArrayCopyImpl(const vtkm::cont::ArrayHandle& source, std::true_type, std::true_type) { - ArrayCopyValueTypeCheck(); - ArrayCopyValueTypeCheck(); - detail::ArrayCopyConcreteSrc{}(source, destination); } diff --git a/vtkm/cont/ArrayExtractComponent.h b/vtkm/cont/ArrayExtractComponent.h index 4d412a51d..12dc1eeaa 100644 --- a/vtkm/cont/ArrayExtractComponent.h +++ b/vtkm/cont/ArrayExtractComponent.h @@ -37,7 +37,7 @@ namespace internal // is defined rather than where it is resolved. This causes problems when extracting // components of, say, an ArrayHandleMultiplexer holding an ArrayHandleSOA. template -vtkm::cont::ArrayHandleStride::BaseComponentType> +vtkm::cont::ArrayHandleStride::BaseComponentType> ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle& src, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy) @@ -53,7 +53,7 @@ ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle& src, << vtkm::cont::TypeToString>() << " requires an inefficient memory copy."); - using BaseComponentType = typename vtkm::internal::SafeVecTraits::BaseComponentType; + using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; vtkm::Id numValues = src.GetNumberOfValues(); vtkm::cont::ArrayHandleBasic dest; dest.Allocate(numValues); @@ -78,10 +78,10 @@ template struct ArrayExtractComponentImpl : ArrayExtractComponentImplInefficient { template - vtkm::cont::ArrayHandleStride::BaseComponentType> - operator()(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy) const + vtkm::cont::ArrayHandleStride::BaseComponentType> operator()( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy) const { // This is the slow "default" implementation. ArrayHandle implementations should provide // more efficient overloads where applicable. @@ -93,15 +93,13 @@ template <> struct ArrayExtractComponentImpl { template - vtkm::cont::ArrayHandleStride::BaseComponentType> - operator()(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy) const + vtkm::cont::ArrayHandleStride::BaseComponentType> operator()( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy) const { - return this->DoExtract(src, - componentIndex, - allowCopy, - typename vtkm::internal::SafeVecTraits::HasMultipleComponents{}); + return this->DoExtract( + src, componentIndex, allowCopy, typename vtkm::VecTraits::HasMultipleComponents{}); } private: @@ -112,7 +110,7 @@ private: vtkm::VecTraitsTagSingleComponent) const { VTKM_ASSERT(componentIndex == 0); - using VTraits = vtkm::internal::SafeVecTraits; + using VTraits = vtkm::VecTraits; using TBase = typename VTraits::BaseComponentType; VTKM_STATIC_ASSERT(VTraits::NUM_COMPONENTS == 1); @@ -135,7 +133,7 @@ private: vtkm::CopyFlag allowCopy, vtkm::VecTraitsTagMultipleComponents) const { - using VTraits = vtkm::internal::SafeVecTraits; + using VTraits = vtkm::VecTraits; using T = typename VTraits::ComponentType; constexpr vtkm::IdComponent N = VTraits::NUM_COMPONENTS; @@ -254,10 +252,10 @@ using ArrayExtractComponentIsInefficient = typename std::is_base_of< /// `vtkm::cont::internal::ArrayExtractComponentImpl`. /// template -vtkm::cont::ArrayHandleStride::BaseComponentType> -ArrayExtractComponent(const vtkm::cont::ArrayHandle& src, - vtkm::IdComponent componentIndex, - vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) +vtkm::cont::ArrayHandleStride::BaseComponentType> ArrayExtractComponent( + const vtkm::cont::ArrayHandle& src, + vtkm::IdComponent componentIndex, + vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) { return internal::ArrayExtractComponentImpl{}(src, componentIndex, allowCopy); } diff --git a/vtkm/cont/ArrayGetValues.h b/vtkm/cont/ArrayGetValues.h index e4a19fb14..51e23e444 100644 --- a/vtkm/cont/ArrayGetValues.h +++ b/vtkm/cont/ArrayGetValues.h @@ -120,9 +120,6 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle& ids const vtkm::cont::ArrayHandle& data, vtkm::cont::ArrayHandle& output) { - VTKM_STATIC_ASSERT_MSG( - vtkm::HasVecTraits::value, - "ArrayGetValues can only be used with arrays containing value types with VecTraits defined."); using DataArrayHandle = vtkm::cont::ArrayHandle; using InefficientExtract = vtkm::cont::internal::ArrayExtractComponentIsInefficient; diff --git a/vtkm/cont/ArrayHandle.h b/vtkm/cont/ArrayHandle.h index 09a40f346..6a4467b15 100644 --- a/vtkm/cont/ArrayHandle.h +++ b/vtkm/cont/ArrayHandle.h @@ -752,9 +752,9 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value( std::ostream& out, vtkm::VecTraitsTagMultipleComponents) { - using Traits = vtkm::internal::SafeVecTraits; + using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; - using IsVecOfVec = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; + using IsVecOfVec = typename vtkm::VecTraits::HasMultipleComponents; vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value); out << "("; printSummary_ArrayHandle_Value(Traits::GetComponent(value, 0), out, IsVecOfVec()); @@ -774,10 +774,10 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle_Value( { out << "{"; printSummary_ArrayHandle_Value( - value.first, out, typename vtkm::internal::SafeVecTraits::HasMultipleComponents()); + value.first, out, typename vtkm::VecTraits::HasMultipleComponents()); out << ","; printSummary_ArrayHandle_Value( - value.second, out, typename vtkm::internal::SafeVecTraits::HasMultipleComponents()); + value.second, out, typename vtkm::VecTraits::HasMultipleComponents()); out << "}"; } @@ -793,7 +793,7 @@ VTKM_NEVER_EXPORT VTKM_CONT inline void printSummary_ArrayHandle( { using ArrayType = vtkm::cont::ArrayHandle; using PortalType = typename ArrayType::ReadPortalType; - using IsVec = typename vtkm::internal::SafeVecTraits::HasMultipleComponents; + using IsVec = typename vtkm::VecTraits::HasMultipleComponents; vtkm::Id sz = array.GetNumberOfValues(); diff --git a/vtkm/cont/ArrayHandleCounting.h b/vtkm/cont/ArrayHandleCounting.h index 2840eeaeb..7f2eae8c1 100644 --- a/vtkm/cont/ArrayHandleCounting.h +++ b/vtkm/cont/ArrayHandleCounting.h @@ -77,27 +77,17 @@ private: namespace detail { -template > -struct CanCountImpl; - template -struct CanCountImpl -{ - using TTraits = vtkm::TypeTraits; - static constexpr bool IsNumeric = - !std::is_same::value; - - static constexpr bool value = IsNumeric; -}; - -template -struct CanCountImpl +struct CanCountImpl { using VTraits = vtkm::VecTraits; using BaseType = typename VTraits::BaseComponentType; + using TTraits = vtkm::TypeTraits; + static constexpr bool IsNumeric = + !std::is_same::value; static constexpr bool IsBool = std::is_same::value; - static constexpr bool value = CanCountImpl::value && !IsBool; + static constexpr bool value = IsNumeric && !IsBool; }; } // namespace detail diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index f99303a95..1a817e296 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -87,7 +87,7 @@ public: return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator=(const T& src) { this->DoCopy(src); @@ -104,7 +104,7 @@ public: return result; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator+=(const T& src) { using VTraits = vtkm::VecTraits; @@ -115,7 +115,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator-=(const T& src) { using VTraits = vtkm::VecTraits; @@ -126,7 +126,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator*=(const T& src) { using VTraits = vtkm::VecTraits; @@ -137,7 +137,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator/=(const T& src) { using VTraits = vtkm::VecTraits; @@ -148,7 +148,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator%=(const T& src) { using VTraits = vtkm::VecTraits; @@ -159,7 +159,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator&=(const T& src) { using VTraits = vtkm::VecTraits; @@ -170,7 +170,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator|=(const T& src) { using VTraits = vtkm::VecTraits; @@ -181,7 +181,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator^=(const T& src) { using VTraits = vtkm::VecTraits; @@ -192,7 +192,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator>>=(const T& src) { using VTraits = vtkm::VecTraits; @@ -203,7 +203,7 @@ public: } return *this; } - template ::value>::type> + template VTKM_EXEC_CONT RecombineVec& operator<<=(const T& src) { using VTraits = vtkm::VecTraits; diff --git a/vtkm/cont/ArrayHandleRuntimeVec.h b/vtkm/cont/ArrayHandleRuntimeVec.h index 6006452a9..4143c8bd4 100644 --- a/vtkm/cont/ArrayHandleRuntimeVec.h +++ b/vtkm/cont/ArrayHandleRuntimeVec.h @@ -141,7 +141,7 @@ class Storage, vtkm::cont::StorageTagRunti vtkm::cont::internal::Storage; VTKM_STATIC_ASSERT_MSG( - vtkm::internal::SafeVecTraits::NUM_COMPONENTS == 1, + vtkm::VecTraits::NUM_COMPONENTS == 1, "ArrayHandleRuntimeVec only supports scalars grouped into a single Vec. Nested Vecs can " "still be used with ArrayHandleRuntimeVec. The values are treated as flattened (like " "with VecFlat)."); diff --git a/vtkm/cont/ArrayHandleSOA.h b/vtkm/cont/ArrayHandleSOA.h index 552ab5d5a..d50d64470 100644 --- a/vtkm/cont/ArrayHandleSOA.h +++ b/vtkm/cont/ArrayHandleSOA.h @@ -44,7 +44,6 @@ public: private: using ComponentType = typename ComponentPortalType::ValueType; - VTKM_STATIC_ASSERT(vtkm::HasVecTraits::value); using VTraits = vtkm::VecTraits; VTKM_STATIC_ASSERT((std::is_same::value)); static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS; diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 88b40590f..27c52ffc1 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -82,11 +82,9 @@ inline auto UnknownAHNumberOfComponentsImpl(void* mem) // of a use case for the storage to report the number of components for a static data type. // If that happens, this implementation will need to be modified. template -inline auto UnknownAHNumberOfComponentsImpl(void*) - -> decltype(vtkm::internal::SafeVecTraits::NUM_COMPONENTS) +inline auto UnknownAHNumberOfComponentsImpl(void*) -> decltype(vtkm::VecTraits::NUM_COMPONENTS) { - static constexpr vtkm::IdComponent numComponents = - vtkm::internal::SafeVecTraits::NUM_COMPONENTS; + static constexpr vtkm::IdComponent numComponents = vtkm::VecTraits::NUM_COMPONENTS; return numComponents; } @@ -117,7 +115,7 @@ inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem) // static. If a future `ArrayHandle` type violates this, this code will have to become // more complex. return (vtkm::cont::internal::Storage::GetNumberOfComponents(arrayHandle->GetBuffers()) * - vtkm::VecFlat::ComponentType>::NUM_COMPONENTS); + vtkm::VecFlat::ComponentType>::NUM_COMPONENTS); } // Uses SFINAE to use the number of compnents in VecTraits. @@ -364,14 +362,13 @@ std::shared_ptr UnknownAHNewInstanceBasic(vtkm::VecTraitsTag template std::shared_ptr UnknownAHNewInstanceBasic() { - return UnknownAHNewInstanceBasic(typename vtkm::internal::SafeVecTraits::IsSizeStatic{}); + return UnknownAHNewInstanceBasic(typename vtkm::VecTraits::IsSizeStatic{}); } template std::shared_ptr UnknownAHNewInstanceFloatBasic(vtkm::VecTraitsTagSizeStatic) { - using FloatT = typename vtkm::internal::SafeVecTraits::template ReplaceBaseComponentType< - vtkm::FloatDefault>; + using FloatT = typename vtkm::VecTraits::template ReplaceBaseComponentType; return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic{}); } template @@ -383,8 +380,7 @@ std::shared_ptr UnknownAHNewInstanceFloatBasic(vtkm::VecTrai template std::shared_ptr UnknownAHNewInstanceFloatBasic() { - return UnknownAHNewInstanceFloatBasic( - typename vtkm::internal::SafeVecTraits::IsSizeStatic{}); + return UnknownAHNewInstanceFloatBasic(typename vtkm::VecTraits::IsSizeStatic{}); } template @@ -393,7 +389,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle::BaseComponentType>()) + UnknownAHComponentInfo::Make::BaseComponentType>()) , DeleteFunction(detail::UnknownAHDelete) , Buffers(detail::UnknownAHBuffers) , NewInstance(detail::UnknownAHNewInstance) @@ -1031,8 +1027,8 @@ namespace detail { template ::ComponentType>::NUM_COMPONENTS> + vtkm::IdComponent = + vtkm::VecTraits::ComponentType>::NUM_COMPONENTS> struct UnknownArrayHandleRuntimeVecAsBasic { VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*, diff --git a/vtkm/cont/internal/MapArrayPermutation.cxx b/vtkm/cont/internal/MapArrayPermutation.cxx index cb3512df0..82de78f0f 100644 --- a/vtkm/cont/internal/MapArrayPermutation.cxx +++ b/vtkm/cont/internal/MapArrayPermutation.cxx @@ -36,7 +36,6 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField InputPortalType inputPortal, OutputType& output) const { - VTKM_STATIC_ASSERT(vtkm::HasVecTraits::value); if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues())) { output = inputPortal.Get(permutationIndex); diff --git a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx index a2da0ad5a..fdb4e7bd6 100644 --- a/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx +++ b/vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx @@ -76,8 +76,8 @@ struct PassThrough : vtkm::worklet::WorkletMapField OutValue& outValue, vtkm::IdComponent& outIndex) const { - using VTraitsIn = vtkm::internal::SafeVecTraits; - using VTraitsOut = vtkm::internal::SafeVecTraits; + using VTraitsIn = vtkm::VecTraits; + using VTraitsOut = vtkm::VecTraits; VTraitsOut::SetComponent(outValue, outIndex, VTraitsIn::GetComponent(inValue, inIndex)); inIndex++; outIndex++; diff --git a/vtkm/internal/ArrayPortalValueReference.h b/vtkm/internal/ArrayPortalValueReference.h index e92340a3f..e7f849d31 100644 --- a/vtkm/internal/ArrayPortalValueReference.h +++ b/vtkm/internal/ArrayPortalValueReference.h @@ -19,39 +19,6 @@ namespace vtkm namespace internal { -namespace detail -{ - -// TODO: VecTraits should just always be supported. See #589. - -template ::value>::type> -VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(const Vec& vec) -{ - return vtkm::VecTraits::GetNumberOfComponents(vec); -} - -VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(...) -{ - return 1; -} - -template ::value>::type> -VTKM_EXEC_CONT inline typename vtkm::VecTraits::ComponentType SafeGetComponent( - const Vec& vec, - vtkm::IdComponent index) -{ - return vtkm::VecTraits::GetComponent(vec, index); -} - -template ::value>::type> -VTKM_EXEC_CONT inline T SafeGetComponent(const T& value, vtkm::IdComponent index) -{ - VTKM_ASSERT(index == 0); - return value; -} - -} // namespace detail - /// \brief A value class for returning setable values of an ArrayPortal /// /// \c ArrayPortal classes have a pair of \c Get and \c Set methods that @@ -350,12 +317,12 @@ struct ArrayPortalValueReference // cannot write components one at a time. VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const { - return detail::SafeGetNumberOfComponents(static_cast(*this)); + return vtkm::VecTraits::GetNumberOfComponents(this->Get()); } - VTKM_EXEC_CONT auto operator[](vtkm::IdComponent index) const - -> decltype(detail::SafeGetComponent(std::declval(), index)) + VTKM_EXEC_CONT + typename vtkm::VecTraits::ComponentType operator[](vtkm::IdComponent index) const { - return detail::SafeGetComponent(static_cast(*this), index); + return vtkm::VecTraits::GetComponent(this->Get(), index); } private: diff --git a/vtkm/io/internal/VTKDataSetTypes.h b/vtkm/io/internal/VTKDataSetTypes.h index eaeb811ea..483573a6f 100644 --- a/vtkm/io/internal/VTKDataSetTypes.h +++ b/vtkm/io/internal/VTKDataSetTypes.h @@ -242,11 +242,9 @@ inline void SelectTypeAndCall(DataType dtype, assert(false); } } + } } } // namespace vtkm::io::internal -VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8) -VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType) - #endif // vtk_m_io_internal_VTKDataSetTypes_h diff --git a/vtkm/testing/Testing.h b/vtkm/testing/Testing.h index ed0217f67..36cb38616 100644 --- a/vtkm/testing/Testing.h +++ b/vtkm/testing/Testing.h @@ -624,12 +624,8 @@ namespace detail template struct TestEqualImpl { - template - VTKM_EXEC_CONT bool DoIt(T1 vector1, - T2 vector2, - vtkm::Float64 tolerance, - Dimensionality1, - Dimensionality2) const + template + VTKM_EXEC_CONT bool DoIt(T1 vector1, T2 vector2, vtkm::Float64 tolerance, IsBase1, IsBase2) const { using Traits1 = vtkm::VecTraits; using Traits2 = vtkm::VecTraits; @@ -658,8 +654,8 @@ struct TestEqualImpl VTKM_EXEC_CONT bool DoIt(T1 scalar1, T2 scalar2, vtkm::Float64 tolerance, - vtkm::TypeTraitsScalarTag, - vtkm::TypeTraitsScalarTag) const + std::true_type, + std::true_type) const { // Do all comparisons using 64-bit floats. return test_equal( @@ -668,11 +664,13 @@ struct TestEqualImpl VTKM_EXEC_CONT bool operator()(T1 value1, T2 value2, vtkm::Float64 tolerance) const { + using Base1 = typename vtkm::VecTraits::BaseComponentType; + using Base2 = typename vtkm::VecTraits::BaseComponentType; return this->DoIt(value1, value2, tolerance, - typename vtkm::TypeTraits::DimensionalityTag(), - typename vtkm::TypeTraits::DimensionalityTag()); + typename std::is_same::type{}, + typename std::is_same::type{}); } }; diff --git a/vtkm/testing/UnitTestVecTraits.cxx b/vtkm/testing/UnitTestVecTraits.cxx index 9642670b8..85a08c885 100644 --- a/vtkm/testing/UnitTestVecTraits.cxx +++ b/vtkm/testing/UnitTestVecTraits.cxx @@ -17,12 +17,18 @@ namespace static constexpr vtkm::Id MAX_VECTOR_SIZE = 5; static constexpr vtkm::Id VecInit[MAX_VECTOR_SIZE] = { 42, 54, 67, 12, 78 }; -void ExpectTrueType(std::true_type) {} - -void ExpectFalseType(std::false_type) {} - struct TypeWithoutVecTraits { + vtkm::Id Value = -1; + + TypeWithoutVecTraits() = default; + + TypeWithoutVecTraits(vtkm::Id value) + : Value(value) + { + } + + operator vtkm::Id() const { return this->Value; } }; struct TestVecTypeFunctor @@ -30,9 +36,6 @@ struct TestVecTypeFunctor template void operator()(const T&) const { - // Make sure that VecTraits actually exists - ExpectTrueType(vtkm::HasVecTraits()); - using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; VTKM_TEST_ASSERT(Traits::NUM_COMPONENTS <= MAX_VECTOR_SIZE, @@ -59,8 +62,8 @@ void TestVecTraits() vtkm::testing::Testing::TryTypes(test); std::cout << "vtkm::Vec" << std::endl; test(vtkm::Vec()); - - ExpectFalseType(vtkm::HasVecTraits()); + std::cout << "TypeWithoutVecTraits" << std::endl; + test(TypeWithoutVecTraits{}); vtkm::testing::TestVecComponentsTag(); vtkm::testing::TestVecComponentsTag(); @@ -69,6 +72,7 @@ void TestVecTraits() vtkm::testing::TestVecComponentsTag>(); vtkm::testing::TestScalarComponentsTag(); vtkm::testing::TestScalarComponentsTag(); + vtkm::testing::TestScalarComponentsTag(); } } // anonymous namespace diff --git a/vtkm/testing/VecTraitsTests.h b/vtkm/testing/VecTraitsTests.h index e84db5b72..0bec632a8 100644 --- a/vtkm/testing/VecTraitsTests.h +++ b/vtkm/testing/VecTraitsTests.h @@ -47,6 +47,12 @@ inline void CompareDimensionalityTags(vtkm::TypeTraitsVectorTag, { // If we are here, everything is fine. } +inline void CompareDimensionalityTags(vtkm::TypeTraitsUnknownTag, vtkm::VecTraitsTagSingleComponent) +{ + // If we are here, type traits are probably not defined (and default to unknown). In this case, + // we expect VecTraits to have the default implementation, in which case it is treated as a + // single component. +} template inline void CheckIsStatic(const T&, vtkm::VecTraitsTagSizeStatic) @@ -73,6 +79,12 @@ struct VecIsWritable> using type = std::false_type; }; +template +struct VecIsWritable*> +{ + using type = std::false_type; +}; + // Part of TestVecTypeImpl that writes to the Vec type template static void TestVecTypeWritableImpl(const T& inVector, @@ -150,8 +162,9 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, } // This will fail to compile if the tags are wrong. - detail::CompareDimensionalityTags(typename vtkm::TypeTraits::DimensionalityTag(), - typename vtkm::VecTraits::HasMultipleComponents()); + detail::CompareDimensionalityTags( + typename vtkm::TypeTraits>::DimensionalityTag(), + typename vtkm::VecTraits::HasMultipleComponents()); TestVecTypeWritableImpl( inVector, vectorCopy, outVector, typename VecIsWritable::type()); @@ -159,7 +172,9 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, // Compiler checks for base component types using BaseComponentType = typename vtkm::VecTraits::BaseComponentType; VTKM_STATIC_ASSERT((std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value)); + vtkm::TypeTraitsScalarTag>::value) || + (std::is_same::DimensionalityTag, + vtkm::TypeTraitsUnknownTag>::value)); VTKM_STATIC_ASSERT((std::is_same::BaseComponentType, BaseComponentType>::value)); @@ -167,12 +182,12 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, using ReplaceWithVecComponent = typename vtkm::VecTraits::template ReplaceComponentType>; VTKM_STATIC_ASSERT( - (std::is_same::DimensionalityTag, + (std::is_same>::DimensionalityTag, vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, vtkm::Vec>::value) || - (std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value && + (!std::is_same>::DimensionalityTag, + vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, char>::value)); VTKM_STATIC_ASSERT( (std::is_same::BaseComponentType, @@ -180,12 +195,12 @@ static void TestVecTypeImpl(const typename std::remove_const::type& inVector, using ReplaceBaseComponent = typename vtkm::VecTraits::template ReplaceBaseComponentType; VTKM_STATIC_ASSERT( - (std::is_same::DimensionalityTag, + (std::is_same>::DimensionalityTag, vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, vtkm::Vec>::value) || - (std::is_same::DimensionalityTag, - vtkm::TypeTraitsScalarTag>::value && + (!std::is_same>::DimensionalityTag, + vtkm::TypeTraitsVectorTag>::value && std::is_same::ComponentType, short>::value)); VTKM_STATIC_ASSERT(( std::is_same::BaseComponentType, short>::value)); @@ -227,6 +242,13 @@ static void TestVecType(const T& inVector, T& outVector) { detail::TestVecTypeImpl(inVector, outVector); detail::TestVecTypeImpl(inVector, outVector); + // The local pointer variables are for some weirdness about `TestVecTypeImpl` taking references + // of its argument type. + T* inPointer = const_cast(&inVector); + T* outPointer = &outVector; + detail::TestVecTypeImpl(inPointer, outPointer); + VTKM_STATIC_ASSERT_MSG((std::is_base_of, vtkm::VecTraits>::value), + "Constant pointer should have same implementation as pointer."); } /// Checks to make sure that the HasMultipleComponents tag is actually for a From 87aff6cdef50718bc61c42fadab3142dc690490f Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 16 Mar 2023 16:05:28 -0400 Subject: [PATCH 59/64] ci,hip,tags: remove build tag for hip build --- .gitlab/ci/ubuntu2004.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab/ci/ubuntu2004.yml b/.gitlab/ci/ubuntu2004.yml index 16d3bc189..ef0534144 100644 --- a/.gitlab/ci/ubuntu2004.yml +++ b/.gitlab/ci/ubuntu2004.yml @@ -62,7 +62,6 @@ test:ubuntu2004_kokkos: build:ubuntu2004_hip_kokkos: tags: - - build - vtkm - docker - linux-x86_64 @@ -93,7 +92,6 @@ build:ubuntu2004_hip_kokkos: test:ubuntu2004_hip_kokkos: tags: - - build - vtkm - docker - linux-x86_64 From 6a516de22e6040b71d83382a1f1878188a2ebacf Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Mon, 20 Mar 2023 10:58:28 -0400 Subject: [PATCH 60/64] Add entry for change log. --- docs/changelog/visit-file-reader.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/changelog/visit-file-reader.md diff --git a/docs/changelog/visit-file-reader.md b/docs/changelog/visit-file-reader.md new file mode 100644 index 000000000..389e73871 --- /dev/null +++ b/docs/changelog/visit-file-reader.md @@ -0,0 +1,3 @@ +# Added a reader for VisIt files. + +A VisIt file is a text file that contains the path and filename of a number of VTK files. This provides a convenient way to load `vtkm::cont::PartitionedDataSet` data from VTK files. The first line of the file is the keyword `!NBLOCKS ` that specifies the number of VTK files to be read. From 3ab9e2ba753a5024d593fcc366870219b980e904 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 21 Mar 2023 13:33:30 -0600 Subject: [PATCH 61/64] Update clip with implicit function filter's field map MR !2969 was meant to update the clip filters such that their field mapping works on any field type and preserves the value type. Although this was done for `ClipWithField`, it was not fully implemented for `ClipWithImplicitFunction`. These changes update `ClipWithImplicitFunction` to match its sibling. --- vtkm/filter/contour/ClipWithImplicitFunction.cxx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vtkm/filter/contour/ClipWithImplicitFunction.cxx b/vtkm/filter/contour/ClipWithImplicitFunction.cxx index c135e8e83..24f2f6991 100644 --- a/vtkm/filter/contour/ClipWithImplicitFunction.cxx +++ b/vtkm/filter/contour/ClipWithImplicitFunction.cxx @@ -29,17 +29,18 @@ bool DoMapField(vtkm::cont::DataSet& result, { if (field.IsPointField()) { + vtkm::cont::UnknownArrayHandle inputArray = field.GetData(); + vtkm::cont::UnknownArrayHandle outputArray = inputArray.NewInstanceBasic(); + auto resolve = [&](const auto& concrete) { // use std::decay to remove const ref from the decltype of concrete. - using T = typename std::decay_t::ValueType; - vtkm::cont::ArrayHandle outputArray; - worklet.ProcessPointField(concrete, outputArray); - result.AddPointField(field.GetName(), outputArray); + using BaseT = typename std::decay_t::ValueType::ComponentType; + auto concreteOut = outputArray.ExtractArrayFromComponents(); + worklet.ProcessPointField(concrete, concreteOut); }; - field.GetData() - .CastAndCallForTypesWithFloatFallback( - resolve); + inputArray.CastAndCallWithExtractedArray(resolve); + result.AddPointField(field.GetName(), outputArray); return true; } else if (field.IsCellField()) From 014c429eb015c6afe6bef964ae4a6f44984cfa61 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 21 Mar 2023 14:01:42 -0600 Subject: [PATCH 62/64] Make divide by volume in particle density estimate a little safer While going through the VTK-m code to identify where a cast-and-call was happening against VTKM_DEFAULT_TYPE_LIST, I ran into a subtle case in `ParticleDensityBase` that was calling a worklet with an `UnknownArrayHandle`. This works OK, but was probably compiling for unnecessary types (for example, vectors). Changed the field resolution to be more intentional. --- vtkm/filter/density_estimate/ParticleDensityBase.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vtkm/filter/density_estimate/ParticleDensityBase.cxx b/vtkm/filter/density_estimate/ParticleDensityBase.cxx index b91c538a6..b37f27a7e 100644 --- a/vtkm/filter/density_estimate/ParticleDensityBase.cxx +++ b/vtkm/filter/density_estimate/ParticleDensityBase.cxx @@ -47,7 +47,10 @@ VTKM_CONT void ParticleDensityBase::DoDivideByVolume( const vtkm::cont::UnknownArrayHandle& density) const { auto volume = this->Spacing[0] * this->Spacing[1] * this->Spacing[2]; - this->Invoke(DivideByVolumeWorklet{ volume }, density); + auto resolve = [&](const auto& concreteDensity) { + this->Invoke(DivideByVolumeWorklet{ volume }, concreteDensity); + }; + this->CastAndCallScalarField(density, resolve); } } // namespace density_estimate } // namespace filter From ff68e44d63f648a6a822a7418ab20055046c61aa Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 21 Mar 2023 14:11:15 -0600 Subject: [PATCH 63/64] Make array component checking safer One of the checks for `BenchmarkFilters` is to test the number of components in field arrays. It did this by using a `CastAndCall` to get the base `ArrayHandle` and check the type. This is unnecessarily complicated and fragile in the case where the base array type cannot be resolved by `CastAndCall`. Instead, just query the `UnknownArrayHandle` for the number of components. --- benchmarking/BenchmarkFilters.cxx | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/benchmarking/BenchmarkFilters.cxx b/benchmarking/BenchmarkFilters.cxx index 093e5c7a4..dcc11f58d 100644 --- a/benchmarking/BenchmarkFilters.cxx +++ b/benchmarking/BenchmarkFilters.cxx @@ -708,29 +708,6 @@ public: } }; -// Get the number of components in a UnknownArrayHandle, ArrayHandle, or Field's -// ValueType. -struct NumberOfComponents -{ - vtkm::IdComponent NumComponents; - - template - VTKM_CONT void operator()(const ArrayHandleT&) - { - using ValueType = typename ArrayHandleT::ValueType; - using Traits = vtkm::VecTraits; - this->NumComponents = Traits::NUM_COMPONENTS; - } - - template - VTKM_CONT static vtkm::IdComponent Check(const DynamicType& obj) - { - NumberOfComponents functor; - vtkm::cont::CastAndCall(obj, functor); - return functor.NumComponents; - } -}; - void FindFields() { if (PointScalarsName.empty()) @@ -739,7 +716,7 @@ void FindFields() { auto field = GetInputDataSet().GetField(i); if (field.GetAssociation() == vtkm::cont::Field::Association::Points && - NumberOfComponents::Check(field) == 1) + field.GetData().GetNumberOfComponentsFlat() == 1) { PointScalarsName = field.GetName(); std::cerr << "[FindFields] Found PointScalars: " << PointScalarsName << "\n"; @@ -754,7 +731,7 @@ void FindFields() { auto field = GetInputDataSet().GetField(i); if (field.GetAssociation() == vtkm::cont::Field::Association::Cells && - NumberOfComponents::Check(field) == 1) + field.GetData().GetNumberOfComponentsFlat() == 1) { CellScalarsName = field.GetName(); std::cerr << "[FindFields] CellScalars: " << CellScalarsName << "\n"; @@ -769,7 +746,7 @@ void FindFields() { auto field = GetInputDataSet().GetField(i); if (field.GetAssociation() == vtkm::cont::Field::Association::Points && - NumberOfComponents::Check(field) == 3) + field.GetData().GetNumberOfComponentsFlat() == 3) { PointVectorsName = field.GetName(); std::cerr << "[FindFields] Found PointVectors: " << PointVectorsName << "\n"; From d8f3e68d1dbb2c631cf479f7184ecc4aa13b3a2e Mon Sep 17 00:00:00 2001 From: Jay Date: Fri, 17 Mar 2023 09:59:27 +0000 Subject: [PATCH 64/64] add distributed statistics --- docs/changelog/statistics-filter.md | 3 +- vtkm/filter/density_estimate/Statistics.cxx | 269 ++++++++++++------ vtkm/filter/density_estimate/Statistics.h | 48 +--- .../density_estimate/testing/CMakeLists.txt | 12 + .../testing/UnitTestStatisticsFilter.cxx | 123 ++++++-- .../testing/UnitTestStatisticsFilterMPI.cxx | 267 +++++++++++++++++ vtkm/filter/density_estimate/vtkm.module | 2 + vtkm/worklet/DescriptiveStatistics.h | 53 +++- .../testing/UnitTestDescriptiveStatistics.cxx | 48 ++++ 9 files changed, 661 insertions(+), 164 deletions(-) create mode 100644 vtkm/filter/density_estimate/testing/UnitTestStatisticsFilterMPI.cxx diff --git a/docs/changelog/statistics-filter.md b/docs/changelog/statistics-filter.md index d20cfa74d..0601c5045 100644 --- a/docs/changelog/statistics-filter.md +++ b/docs/changelog/statistics-filter.md @@ -1,3 +1,4 @@ # New Statistics filter -The statistics filter computes the descriptive statistics of the fields specified by users based on `DescriptiveStatistics`. Users can set `RequiredStatsList` to specify which statistics will be stored in the output data set. +The statistics filter computes the descriptive statistics of the fields specified by users based on `DescriptiveStatistics`. Users can set `RequiredStatsList` to specify which statistics will be stored in the output data set. The statistics filter supports the distributed memory case based on the vtkmdiy, and the process with rank 0 will return the correct final reduced results. + diff --git a/vtkm/filter/density_estimate/Statistics.cxx b/vtkm/filter/density_estimate/Statistics.cxx index 2b9a459f8..4d1c61128 100644 --- a/vtkm/filter/density_estimate/Statistics.cxx +++ b/vtkm/filter/density_estimate/Statistics.cxx @@ -7,9 +7,15 @@ // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ +#include #include #include +#include #include +#ifdef VTKM_ENABLE_MPI +#include +#include +#endif namespace vtkm { @@ -17,98 +23,193 @@ namespace filter { namespace density_estimate { +//refer to this paper https://www.osti.gov/servlets/purl/1028931 +//for the math of computing distributed statistics +//using anonymous namespace +namespace +{ +using StatValueType = vtkm::worklet::DescriptiveStatistics::StatState; +class DistributedStatistics +{ + vtkm::cont::ArrayHandle localStatisticsValues; + +public: + DistributedStatistics(vtkm::Id numLocalBlocks) + { + this->localStatisticsValues.Allocate(numLocalBlocks); + } + + void SetLocalStatistics(vtkm::Id index, StatValueType& value) + { + this->localStatisticsValues.WritePortal().Set(index, value); + } + + StatValueType ReduceStatisticsDiy() const + { + using Algorithm = vtkm::cont::Algorithm; + // The StatValueType struct overloads the + operator. Reduce is using to properly + // combine statistical measures such as mean, standard deviation, and others. So, + // the Reduce is computing the global statistics over partitions rather than a + // simple sum. + StatValueType statePerRank = Algorithm::Reduce(this->localStatisticsValues, StatValueType{}); + StatValueType stateResult = statePerRank; +#ifdef VTKM_ENABLE_MPI + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + if (comm.size() == 1) + { + return statePerRank; + } + + vtkmdiy::Master master( + comm, + 1, + -1, + []() -> void* { return new StatValueType(); }, + [](void* ptr) { delete static_cast(ptr); }); + + vtkmdiy::ContiguousAssigner assigner(/*num ranks*/ comm.size(), + /*global-num-blocks*/ comm.size()); + vtkmdiy::RegularDecomposer decomposer( + /*dims*/ 1, vtkmdiy::interval(0, assigner.nblocks() - 1), assigner.nblocks()); + decomposer.decompose(comm.rank(), assigner, master); + VTKM_ASSERT(static_cast(master.size()) == 1); + + //adding data into master + *master.block(0) = statePerRank; + auto callback = [](StatValueType* result, + const vtkmdiy::ReduceProxy& srp, + const vtkmdiy::RegularMergePartners&) { + const auto selfid = srp.gid(); + // 1. dequeue. + std::vector incoming; + srp.incoming(incoming); + for (const int gid : incoming) + { + if (gid != selfid) + { + StatValueType inData; + srp.dequeue(gid, inData); + *result = *result + inData; + } + } + // 2. enqueue + for (int cc = 0; cc < srp.out_link().size(); ++cc) + { + auto target = srp.out_link().target(cc); + if (target.gid != selfid) + { + srp.enqueue(target, *result); + } + } + }; + + vtkmdiy::RegularMergePartners partners(decomposer, /*k=*/2); + vtkmdiy::reduce(master, assigner, partners, callback); + + //only rank 0 process returns the correct results + if (master.local(0)) + { + stateResult = *master.block(0); + } + else + { + stateResult = StatValueType(); + } +#endif + return stateResult; + } +}; +} + +vtkm::FloatDefault ExtractVariable(vtkm::cont::DataSet dataset, const std::string& statName) +{ + vtkm::cont::ArrayHandle array; + dataset.GetField(statName).GetData().AsArrayHandle(array); + vtkm::cont::ArrayHandle::ReadPortalType portal = array.ReadPortal(); + vtkm::FloatDefault value = portal.Get(0); + return value; +} + +template +VTKM_CONT vtkm::cont::ArrayHandle SaveDataIntoArray(const T value) +{ + vtkm::cont::ArrayHandle stat; + stat.Allocate(1); + stat.WritePortal().Set(0, static_cast(value)); + return stat; +} + +VTKM_CONT StatValueType GetStatValueFromDataSet(const vtkm::cont::DataSet& data) +{ + vtkm::FloatDefault N = ExtractVariable(data, "N"); + vtkm::FloatDefault Min = ExtractVariable(data, "Min"); + vtkm::FloatDefault Max = ExtractVariable(data, "Max"); + vtkm::FloatDefault Sum = ExtractVariable(data, "Sum"); + vtkm::FloatDefault Mean = ExtractVariable(data, "Mean"); + vtkm::FloatDefault M2 = ExtractVariable(data, "M2"); + vtkm::FloatDefault M3 = ExtractVariable(data, "M3"); + vtkm::FloatDefault M4 = ExtractVariable(data, "M4"); + return StatValueType(N, Min, Max, Sum, Mean, M2, M3, M4); +} + +template +VTKM_CONT void SaveIntoDataSet(StatValueType& statValue, + DataSetType& output, + vtkm::cont::Field::Association association) +{ + output.AddField({ "N", association, SaveDataIntoArray(statValue.N()) }); + output.AddField({ "Min", association, SaveDataIntoArray(statValue.Min()) }); + output.AddField({ "Max", association, SaveDataIntoArray(statValue.Max()) }); + output.AddField({ "Sum", association, SaveDataIntoArray(statValue.Sum()) }); + output.AddField({ "Mean", association, SaveDataIntoArray(statValue.Mean()) }); + output.AddField({ "M2", association, SaveDataIntoArray(statValue.M2()) }); + output.AddField({ "M3", association, SaveDataIntoArray(statValue.M3()) }); + output.AddField({ "M4", association, SaveDataIntoArray(statValue.M4()) }); + output.AddField({ "SampleStddev", association, SaveDataIntoArray(statValue.SampleStddev()) }); + output.AddField( + { "PopulationStddev", association, SaveDataIntoArray(statValue.PopulationStddev()) }); + output.AddField({ "SampleVariance", association, SaveDataIntoArray(statValue.SampleVariance()) }); + output.AddField( + { "PopulationVariance", association, SaveDataIntoArray(statValue.PopulationVariance()) }); + output.AddField({ "Skewness", association, SaveDataIntoArray(statValue.Skewness()) }); + output.AddField({ "Kurtosis", association, SaveDataIntoArray(statValue.Kurtosis()) }); +} VTKM_CONT vtkm::cont::DataSet Statistics::DoExecute(const vtkm::cont::DataSet& inData) { vtkm::worklet::DescriptiveStatistics worklet; vtkm::cont::DataSet output; - - auto resolveType = [&](const auto& concrete) { - auto result = worklet.Run(concrete); - - for (size_t i = 0; i < RequiredStatsList.size(); i++) - { - vtkm::cont::ArrayHandle stat; - stat.Allocate(1); - Stats statEnum = RequiredStatsList[i]; - - switch (statEnum) - { - case Stats::N: - { - stat.WritePortal().Set(0, static_cast(result.N())); - break; - } - case Stats::Min: - { - stat.WritePortal().Set(0, static_cast(result.Min())); - break; - } - case Stats::Max: - { - stat.WritePortal().Set(0, static_cast(result.Max())); - break; - } - case Stats::Sum: - { - stat.WritePortal().Set(0, static_cast(result.Sum())); - break; - } - case Stats::Mean: - { - stat.WritePortal().Set(0, static_cast(result.Mean())); - break; - } - case Stats::SampleStdDev: - { - stat.WritePortal().Set(0, static_cast(result.SampleStddev())); - break; - } - case Stats::PopulationStdDev: - { - stat.WritePortal().Set(0, static_cast(result.PopulationStddev())); - break; - } - case Stats::SampleVariance: - { - stat.WritePortal().Set(0, static_cast(result.SampleVariance())); - break; - } - case Stats::PopulationVariance: - { - stat.WritePortal().Set(0, static_cast(result.PopulationVariance())); - break; - } - case Stats::Skewness: - { - stat.WritePortal().Set(0, static_cast(result.Skewness())); - break; - } - case Stats::Kurtosis: - { - stat.WritePortal().Set(0, static_cast(result.Kurtosis())); - break; - } - default: - { - throw vtkm::cont::ErrorFilterExecution( - "Unsupported statistics variable in statistics filter."); - } - } - - output.AddField({ this->StatsName[static_cast(statEnum)], - vtkm::cont::Field::Association::WholeDataSet, - stat }); - } - }; - const auto& fieldArray = this->GetFieldFromDataSet(inData).GetData(); - fieldArray - .CastAndCallForTypesWithFloatFallback( - resolveType); - + vtkm::cont::ArrayHandle input; + //TODO: GetFieldFromDataSet will throw an exception if the targeted Field does not exist in the data set + ArrayCopyShallowIfPossible(this->GetFieldFromDataSet(inData).GetData(), input); + StatValueType result = worklet.Run(input); + SaveIntoDataSet( + result, output, vtkm::cont::Field::Association::WholeDataSet); return output; } +VTKM_CONT vtkm::cont::PartitionedDataSet Statistics::DoExecutePartitions( + const vtkm::cont::PartitionedDataSet& input) +{ + // This operation will create a partitioned data set with a partition matching each input partition + // containing the local statistics. It will iterate through each partition in the input and call the + // DoExecute function. This is the same behavior as if we did not implement `DoExecutePartitions`. + // It has the added benefit of optimizations for concurrently executing small blocks. + vtkm::cont::PartitionedDataSet localOutput = this->FilterField::DoExecutePartitions(input); + vtkm::Id numPartitions = input.GetNumberOfPartitions(); + DistributedStatistics helper(numPartitions); + for (vtkm::Id i = 0; i < numPartitions; ++i) + { + const vtkm::cont::DataSet& localDS = localOutput.GetPartition(i); + StatValueType localStatisticsValues = GetStatValueFromDataSet(localDS); + helper.SetLocalStatistics(i, localStatisticsValues); + } + StatValueType result = helper.ReduceStatisticsDiy(); + vtkm::cont::PartitionedDataSet output; + SaveIntoDataSet( + result, output, vtkm::cont::Field::Association::Global); + return output; +} } // namespace density_estimate } // namespace filter } // namespace vtkm diff --git a/vtkm/filter/density_estimate/Statistics.h b/vtkm/filter/density_estimate/Statistics.h index 769fcb00f..a10afeaac 100644 --- a/vtkm/filter/density_estimate/Statistics.h +++ b/vtkm/filter/density_estimate/Statistics.h @@ -25,54 +25,10 @@ namespace density_estimate /// class VTKM_FILTER_DENSITY_ESTIMATE_EXPORT Statistics : public vtkm::filter::FilterField { -public: - enum struct Stats - { - N = 0, - Min, - Max, - Sum, - Mean, - SampleStdDev, - PopulationStdDev, - SampleVariance, - PopulationVariance, - Skewness, - Kurtosis - }; - - - /// \{ - /// \brief The output statistical variables for executing the statistics filter. - /// - void SetRequiredStats(const std::vector StatsList) { RequiredStatsList = StatsList; } - const std::vector& GetRequiredStats() const { return this->RequiredStatsList; } - /// \} private: VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override; - std::vector RequiredStatsList{ Stats::N, - Stats::Min, - Stats::Max, - Stats::Sum, - Stats::Mean, - Stats::SampleStdDev, - Stats::PopulationStdDev, - Stats::SampleVariance, - Stats::PopulationVariance, - Stats::Skewness, - Stats::Kurtosis }; - // This string vector stores variables names stored in the output dataset - std::vector StatsName{ "N", - "Min", - "Max", - "Sum", - "Mean", - "SampleStddev", - "PopulationStdDev", - "SampleVariance", - "PopulationVariance", - "Skewness", - "Kurtosis" }; + VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions( + const vtkm::cont::PartitionedDataSet& inData) override; }; } // namespace density_estimate } // namespace filter diff --git a/vtkm/filter/density_estimate/testing/CMakeLists.txt b/vtkm/filter/density_estimate/testing/CMakeLists.txt index d36470d03..21b8ce4d9 100644 --- a/vtkm/filter/density_estimate/testing/CMakeLists.txt +++ b/vtkm/filter/density_estimate/testing/CMakeLists.txt @@ -15,6 +15,7 @@ set(unit_tests UnitTestNDHistogramFilter.cxx UnitTestPartitionedDataSetHistogramFilter.cxx UnitTestStatisticsFilter.cxx + UnitTestStatisticsFilterMPI.cxx ) set(unit_tests_device @@ -31,3 +32,14 @@ vtkm_unit_tests( LIBRARIES ${libraries} USE_VTKM_JOB_POOL ) + +if (VTKm_ENABLE_MPI) + set(mpi_unit_tests + UnitTestStatisticsFilterMPI.cxx + ) + vtkm_unit_tests( + MPI + DEVICE_SOURCES ${mpi_unit_tests} + USE_VTKM_JOB_POOL + ) +endif() diff --git a/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilter.cxx b/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilter.cxx index 15dade562..8a5fa557b 100644 --- a/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilter.cxx +++ b/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilter.cxx @@ -8,16 +8,16 @@ // PURPOSE. See the above copyright notice for more information. //============================================================================ -#include - +#include #include #include - +#include +#include namespace { - -vtkm::FloatDefault getStatsFromArray(vtkm::cont::DataSet dataset, const std::string statName) +template +vtkm::FloatDefault getStatsFromDataSet(const DataSetType& dataset, const std::string statName) { vtkm::cont::ArrayHandle array; dataset.GetField(statName).GetData().AsArrayHandle(array); @@ -30,56 +30,127 @@ void TestStatisticsPartial() { vtkm::cont::DataSet dataSet; constexpr vtkm::FloatDefault N = 1000; - // the number is from 0 to 999 - auto scalaArray = + auto scalarArrayCounting = vtkm::cont::ArrayHandleCounting(0.0f, 1.0f, static_cast(N)); - dataSet.AddPointField("scalarField", scalaArray); + vtkm::cont::ArrayHandle scalarArray; + vtkm::cont::ArrayCopy(scalarArrayCounting, scalarArray); + dataSet.AddPointField("scalarField", scalarArray); using STATS = vtkm::filter::density_estimate::Statistics; STATS statisticsFilter; - - //set required states - std::vector RequiredStatsList{ STATS::Stats::N, STATS::Stats::Sum, - STATS::Stats::Mean, STATS::Stats::SampleVariance, - STATS::Stats::Skewness, STATS::Stats::Kurtosis }; - - //default RequiredStatsList contains all statistics variables - statisticsFilter.SetRequiredStats(RequiredStatsList); using AsscoType = vtkm::cont::Field::Association; - statisticsFilter.SetActiveField("scalarField", AsscoType::Points); - - // We use the same test cases with the UnitTestDescriptiveStatistics.h vtkm::cont::DataSet resultDataSet = statisticsFilter.Execute(dataSet); - vtkm::FloatDefault NValueFromFilter = getStatsFromArray(resultDataSet, "N"); + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(resultDataSet, "N"); VTKM_TEST_ASSERT(test_equal(NValueFromFilter, N)); - vtkm::FloatDefault SumFromFilter = getStatsFromArray(resultDataSet, "Sum"); + vtkm::FloatDefault MinValueFromFilter = getStatsFromDataSet(resultDataSet, "Min"); + VTKM_TEST_ASSERT(test_equal(MinValueFromFilter, 0)); + + vtkm::FloatDefault MaxValueFromFilter = getStatsFromDataSet(resultDataSet, "Max"); + VTKM_TEST_ASSERT(test_equal(MaxValueFromFilter, N - 1)); + + vtkm::FloatDefault SumFromFilter = getStatsFromDataSet(resultDataSet, "Sum"); VTKM_TEST_ASSERT(test_equal(SumFromFilter, N * (N - 1) / 2)); - vtkm::FloatDefault MeanFromFilter = getStatsFromArray(resultDataSet, "Mean"); + vtkm::FloatDefault MeanFromFilter = getStatsFromDataSet(resultDataSet, "Mean"); VTKM_TEST_ASSERT(test_equal(MeanFromFilter, (N - 1) / 2)); - vtkm::FloatDefault SVFromFilter = getStatsFromArray(resultDataSet, "SampleVariance"); + vtkm::FloatDefault SVFromFilter = getStatsFromDataSet(resultDataSet, "SampleVariance"); VTKM_TEST_ASSERT(test_equal(SVFromFilter, 83416.66)); - vtkm::FloatDefault SkewnessFromFilter = getStatsFromArray(resultDataSet, "Skewness"); + vtkm::FloatDefault SstddevFromFilter = getStatsFromDataSet(resultDataSet, "SampleStddev"); + VTKM_TEST_ASSERT(test_equal(SstddevFromFilter, 288.819)); + + vtkm::FloatDefault SkewnessFromFilter = getStatsFromDataSet(resultDataSet, "Skewness"); VTKM_TEST_ASSERT(test_equal(SkewnessFromFilter, 0)); // we use fisher=False when computing the Kurtosis value - vtkm::FloatDefault KurtosisFromFilter = getStatsFromArray(resultDataSet, "Kurtosis"); + vtkm::FloatDefault KurtosisFromFilter = getStatsFromDataSet(resultDataSet, "Kurtosis"); VTKM_TEST_ASSERT(test_equal(KurtosisFromFilter, 1.8)); + + vtkm::FloatDefault PopulationStddev = getStatsFromDataSet(resultDataSet, "PopulationStddev"); + VTKM_TEST_ASSERT(test_equal(PopulationStddev, 288.675)); + + vtkm::FloatDefault PopulationVariance = getStatsFromDataSet(resultDataSet, "PopulationVariance"); + VTKM_TEST_ASSERT(test_equal(PopulationVariance, 83333.3)); } +void TestStatisticsPartition() +{ + std::vector dataSetList; + constexpr vtkm::FloatDefault N = 1000; + + for (vtkm::Id i = 0; i < 10; i++) + { + vtkm::cont::DataSet dataSet; + constexpr vtkm::FloatDefault localN = N / 10; + vtkm::cont::ArrayHandle scalarArray; + scalarArray.Allocate(static_cast(localN)); + auto writePortal = scalarArray.WritePortal(); + for (vtkm::Id j = 0; j < static_cast(localN); j++) + { + writePortal.Set(j, static_cast(i * localN + j)); + } + dataSet.AddPointField("scalarField", scalarArray); + dataSetList.push_back(dataSet); + } + + //adding data sets for testing edge cases + vtkm::cont::DataSet dataSetEmptyField; + dataSetEmptyField.AddPointField("scalarField", vtkm::cont::ArrayHandle()); + dataSetList.push_back(dataSetEmptyField); + + vtkm::cont::PartitionedDataSet pds(dataSetList); + using STATS = vtkm::filter::density_estimate::Statistics; + STATS statisticsFilter; + using AsscoType = vtkm::cont::Field::Association; + statisticsFilter.SetActiveField("scalarField", AsscoType::Points); + vtkm::cont::PartitionedDataSet outputPDS = statisticsFilter.Execute(pds); + + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, N)); + + vtkm::FloatDefault MinValueFromFilter = getStatsFromDataSet(outputPDS, "Min"); + VTKM_TEST_ASSERT(test_equal(MinValueFromFilter, 0)); + + vtkm::FloatDefault MaxValueFromFilter = getStatsFromDataSet(outputPDS, "Max"); + VTKM_TEST_ASSERT(test_equal(MaxValueFromFilter, N - 1)); + + vtkm::FloatDefault SumFromFilter = getStatsFromDataSet(outputPDS, "Sum"); + VTKM_TEST_ASSERT(test_equal(SumFromFilter, N * (N - 1) / 2)); + + vtkm::FloatDefault MeanFromFilter = getStatsFromDataSet(outputPDS, "Mean"); + VTKM_TEST_ASSERT(test_equal(MeanFromFilter, (N - 1) / 2)); + + vtkm::FloatDefault SVFromFilter = getStatsFromDataSet(outputPDS, "SampleVariance"); + VTKM_TEST_ASSERT(test_equal(SVFromFilter, 83416.66)); + + vtkm::FloatDefault SstddevFromFilter = getStatsFromDataSet(outputPDS, "SampleStddev"); + VTKM_TEST_ASSERT(test_equal(SstddevFromFilter, 288.819)); + + vtkm::FloatDefault SkewnessFromFilter = getStatsFromDataSet(outputPDS, "Skewness"); + VTKM_TEST_ASSERT(test_equal(SkewnessFromFilter, 0)); + + // we use fisher=False when computing the Kurtosis value + vtkm::FloatDefault KurtosisFromFilter = getStatsFromDataSet(outputPDS, "Kurtosis"); + VTKM_TEST_ASSERT(test_equal(KurtosisFromFilter, 1.8)); + + vtkm::FloatDefault PopulationStddev = getStatsFromDataSet(outputPDS, "PopulationStddev"); + VTKM_TEST_ASSERT(test_equal(PopulationStddev, 288.675)); + + vtkm::FloatDefault PopulationVariance = getStatsFromDataSet(outputPDS, "PopulationVariance"); + VTKM_TEST_ASSERT(test_equal(PopulationVariance, 83333.3)); +} void TestStatistics() { TestStatisticsPartial(); + TestStatisticsPartition(); } // TestFieldStatistics } -//More deatiled tests can be found in the UnitTestStatisticsFilter int UnitTestStatisticsFilter(int argc, char* argv[]) { return vtkm::cont::testing::Testing::Run(TestStatistics, argc, argv); diff --git a/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilterMPI.cxx b/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilterMPI.cxx new file mode 100644 index 000000000..414c24f84 --- /dev/null +++ b/vtkm/filter/density_estimate/testing/UnitTestStatisticsFilterMPI.cxx @@ -0,0 +1,267 @@ +//============================================================================ +// 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 + +namespace +{ +vtkm::FloatDefault getStatsFromDataSet(const vtkm::cont::PartitionedDataSet& dataset, + const std::string statName) +{ + vtkm::cont::ArrayHandle array; + dataset.GetField(statName).GetData().AsArrayHandle(array); + vtkm::cont::ArrayHandle::ReadPortalType portal = array.ReadPortal(); + vtkm::FloatDefault value = portal.Get(0); + return value; +} + +void checkResulst(const vtkm::cont::PartitionedDataSet& outputPDS, vtkm::FloatDefault N) +{ + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, N)); + + vtkm::FloatDefault MinValueFromFilter = getStatsFromDataSet(outputPDS, "Min"); + VTKM_TEST_ASSERT(test_equal(MinValueFromFilter, 0)); + + vtkm::FloatDefault MaxValueFromFilter = getStatsFromDataSet(outputPDS, "Max"); + VTKM_TEST_ASSERT(test_equal(MaxValueFromFilter, N - 1)); + + vtkm::FloatDefault SumFromFilter = getStatsFromDataSet(outputPDS, "Sum"); + VTKM_TEST_ASSERT(test_equal(SumFromFilter, N * (N - 1) / 2)); + + vtkm::FloatDefault MeanFromFilter = getStatsFromDataSet(outputPDS, "Mean"); + VTKM_TEST_ASSERT(test_equal(MeanFromFilter, (N - 1) / 2)); + + vtkm::FloatDefault SVFromFilter = getStatsFromDataSet(outputPDS, "SampleVariance"); + VTKM_TEST_ASSERT(test_equal(SVFromFilter, 83416.66)); + + vtkm::FloatDefault SstddevFromFilter = getStatsFromDataSet(outputPDS, "SampleStddev"); + VTKM_TEST_ASSERT(test_equal(SstddevFromFilter, 288.819)); + + vtkm::FloatDefault SkewnessFromFilter = getStatsFromDataSet(outputPDS, "Skewness"); + VTKM_TEST_ASSERT(test_equal(SkewnessFromFilter, 0)); + + // we use fisher=False when computing the Kurtosis value + vtkm::FloatDefault KurtosisFromFilter = getStatsFromDataSet(outputPDS, "Kurtosis"); + VTKM_TEST_ASSERT(test_equal(KurtosisFromFilter, 1.8)); + + vtkm::FloatDefault PopulationStddev = getStatsFromDataSet(outputPDS, "PopulationStddev"); + VTKM_TEST_ASSERT(test_equal(PopulationStddev, 288.675)); + + vtkm::FloatDefault PopulationVariance = getStatsFromDataSet(outputPDS, "PopulationVariance"); + VTKM_TEST_ASSERT(test_equal(PopulationVariance, 83333.3)); +} + +void TestStatisticsMPISingleDataSet() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + constexpr vtkm::FloatDefault N = 1000; + vtkm::Id numProcs = comm.size(); + + vtkm::Id workloadBase = static_cast(N / numProcs); + vtkm::Id workloadActual = workloadBase; + if (static_cast(N) % numProcs != 0) + { + //updating the workload for last one + if (comm.rank() == numProcs - 1) + { + workloadActual = workloadActual + (static_cast(N) % numProcs); + } + } + + vtkm::cont::ArrayHandle scalarArray; + scalarArray.Allocate(static_cast(workloadActual)); + auto writePortal = scalarArray.WritePortal(); + for (vtkm::Id i = 0; i < static_cast(workloadActual); i++) + { + writePortal.Set(i, static_cast(workloadBase * comm.rank() + i)); + } + + vtkm::cont::DataSet dataSet; + dataSet.AddPointField("scalarField", scalarArray); + + using STATS = vtkm::filter::density_estimate::Statistics; + STATS statisticsFilter; + + using AsscoType = vtkm::cont::Field::Association; + statisticsFilter.SetActiveField("scalarField", AsscoType::Points); + std::vector dataSetList; + dataSetList.push_back(dataSet); + auto pds = vtkm::cont::PartitionedDataSet(dataSetList); + vtkm::cont::PartitionedDataSet outputPDS = statisticsFilter.Execute(pds); + + if (comm.rank() == 0) + { + checkResulst(outputPDS, N); + } + else + { + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, 0)); + } +} + +void TestStatisticsMPIPartitionDataSets() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + constexpr vtkm::FloatDefault N = 1000; + vtkm::Id numProcs = comm.size(); + + vtkm::Id workloadPerRankBase = static_cast(N / numProcs); + vtkm::Id workloadPerRankActual = workloadPerRankBase; + + if (static_cast(N) % numProcs != 0) + { + //updating the workload for last one + if (comm.rank() == numProcs - 1) + { + workloadPerRankActual = workloadPerRankActual + (static_cast(N) % numProcs); + } + } + + vtkm::Id numPartitions = 2; + vtkm::Id workloadPerPartition0 = workloadPerRankActual / numPartitions; + vtkm::Id workloadPerPartition1 = workloadPerRankActual - workloadPerPartition0; + + vtkm::Id offsetRank = workloadPerRankBase * comm.rank(); + std::vector dataSetList; + + vtkm::cont::ArrayHandle scalarArray0; + scalarArray0.Allocate(static_cast(workloadPerPartition0)); + auto writePortal0 = scalarArray0.WritePortal(); + vtkm::cont::DataSet dataSet0; + + for (vtkm::Id i = 0; i < workloadPerPartition0; i++) + { + writePortal0.Set(i, static_cast(offsetRank + i)); + } + + dataSet0.AddPointField("scalarField", scalarArray0); + dataSetList.push_back(dataSet0); + + vtkm::cont::ArrayHandle scalarArray1; + scalarArray1.Allocate(static_cast(workloadPerPartition1)); + auto writePortal1 = scalarArray1.WritePortal(); + vtkm::cont::DataSet dataSet1; + + for (vtkm::Id i = 0; i < workloadPerPartition1; i++) + { + writePortal1.Set(i, static_cast(offsetRank + workloadPerPartition0 + i)); + } + + dataSet1.AddPointField("scalarField", scalarArray1); + dataSetList.push_back(dataSet1); + + auto pds = vtkm::cont::PartitionedDataSet(dataSetList); + + using STATS = vtkm::filter::density_estimate::Statistics; + STATS statisticsFilter; + using AsscoType = vtkm::cont::Field::Association; + statisticsFilter.SetActiveField("scalarField", AsscoType::Points); + + vtkm::cont::PartitionedDataSet outputPDS = statisticsFilter.Execute(pds); + if (comm.rank() == 0) + { + checkResulst(outputPDS, N); + } + else + { + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, 0)); + } +} + +void TestStatisticsMPIDataSetEmpty() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + constexpr vtkm::FloatDefault N = 1000; + vtkm::Id numProcs = comm.size(); + vtkm::Id numEmptyBlock = 1; + vtkm::Id numProcsWithWork = numProcs; + if (numProcs > 1) + { + numProcsWithWork = numProcsWithWork - numEmptyBlock; + } + + vtkm::Id workloadBase = static_cast(N / (numProcsWithWork)); + vtkm::Id workloadActual = workloadBase; + if (static_cast(N) % numProcsWithWork != 0) + { + //updating the workload for last one + if (comm.rank() == numProcsWithWork - 1) + { + workloadActual = workloadActual + (static_cast(N) % numProcsWithWork); + } + } + + vtkm::cont::DataSet dataSet; + vtkm::cont::ArrayHandle scalarArray; + //for the proc with actual work + if (comm.rank() != numProcs - 1) + { + scalarArray.Allocate(static_cast(workloadActual)); + auto writePortal = scalarArray.WritePortal(); + for (vtkm::Id i = 0; i < static_cast(workloadActual); i++) + { + writePortal.Set(i, static_cast(workloadBase * comm.rank() + i)); + } + } + dataSet.AddPointField("scalarField", scalarArray); + + using STATS = vtkm::filter::density_estimate::Statistics; + STATS statisticsFilter; + + using AsscoType = vtkm::cont::Field::Association; + statisticsFilter.SetActiveField("scalarField", AsscoType::Points); + std::vector dataSetList; + dataSetList.push_back(dataSet); + auto pds = vtkm::cont::PartitionedDataSet(dataSetList); + vtkm::cont::PartitionedDataSet outputPDS = statisticsFilter.Execute(pds); + + if (comm.size() == 1) + { + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, 0)); + return; + } + + if (comm.rank() == 0) + { + checkResulst(outputPDS, N); + } + else + { + vtkm::FloatDefault NValueFromFilter = getStatsFromDataSet(outputPDS, "N"); + VTKM_TEST_ASSERT(test_equal(NValueFromFilter, 0)); + } +} + +void TestStatistics() +{ + TestStatisticsMPISingleDataSet(); + TestStatisticsMPIPartitionDataSets(); + TestStatisticsMPIDataSetEmpty(); +} // TestFieldStatistics +} + +//More deatiled tests can be found in the UnitTestStatisticsFilter +int UnitTestStatisticsFilterMPI(int argc, char* argv[]) +{ + vtkmdiy::mpi::environment env(argc, argv); + vtkmdiy::mpi::communicator world; + return vtkm::cont::testing::Testing::Run(TestStatistics, argc, argv); +} diff --git a/vtkm/filter/density_estimate/vtkm.module b/vtkm/filter/density_estimate/vtkm.module index 2bdced389..c66fc406e 100644 --- a/vtkm/filter/density_estimate/vtkm.module +++ b/vtkm/filter/density_estimate/vtkm.module @@ -6,6 +6,8 @@ DEPENDS vtkm_filter_core PRIVATE_DEPENDS vtkm_worklet +OPTIONAL_DEPENDS + MPI::MPI_CXX TEST_DEPENDS vtkm_filter_density_estimate vtkm_source diff --git a/vtkm/worklet/DescriptiveStatistics.h b/vtkm/worklet/DescriptiveStatistics.h index a2ba0cac0..65787b582 100644 --- a/vtkm/worklet/DescriptiveStatistics.h +++ b/vtkm/worklet/DescriptiveStatistics.h @@ -51,12 +51,33 @@ public: { } + VTKM_EXEC_CONT + StatState(T n, T min, T max, T sum, T mean, T M2, T M3, T M4) + : n_(n) + , min_(min) + , max_(max) + , sum_(sum) + , mean_(mean) + , M2_(M2) + , M3_(M3) + , M4_(M4) + { + } + VTKM_EXEC_CONT StatState operator+(const StatState& y) const { const StatState& x = *this; - StatState result; + if (y.n_ == 0) + { + return x; + } + if (x.n_ == 0) + { + return y; + } + StatState result; result.n_ = x.n_ + y.n_; result.min_ = vtkm::Min(x.min_, y.min_); @@ -97,8 +118,7 @@ public: return result; } - VTKM_EXEC_CONT - T N() const { return this->n_; } + VTKM_EXEC_CONT T N() const { return this->n_; } VTKM_EXEC_CONT T Min() const { return this->min_; } @@ -112,6 +132,15 @@ public: VTKM_EXEC_CONT T Mean() const { return this->mean_; } + VTKM_EXEC_CONT + T M2() const { return this->M2_; } + + VTKM_EXEC_CONT + T M3() const { return this->M3_; } + + VTKM_EXEC_CONT + T M4() const { return this->M4_; } + VTKM_EXEC_CONT T SampleStddev() const { return vtkm::Sqrt(this->SampleVariance()); } @@ -121,17 +150,27 @@ public: VTKM_EXEC_CONT T SampleVariance() const { - VTKM_ASSERT(n_ != 1); + if (this->n_ <= 1) + { + return 0; + } return this->M2_ / (this->n_ - 1); } VTKM_EXEC_CONT - T PopulationVariance() const { return this->M2_ / this->n_; } + T PopulationVariance() const + { + if (this->M2_ == 0 || this->n_ == 0) + { + return T(0); + } + return this->M2_ / this->n_; + } VTKM_EXEC_CONT T Skewness() const { - if (this->M2_ == 0) + if (this->M2_ == 0 || this->n_ == 0) // Shamelessly swiped from Boost Math // The limit is technically undefined, but the interpretation here is clear: // A constant dataset has no skewness. @@ -143,7 +182,7 @@ public: VTKM_EXEC_CONT T Kurtosis() const { - if (this->M2_ == 0) + if (this->M2_ == 0 || this->n_ == 0) // Shamelessly swiped from Boost Math // The limit is technically undefined, but the interpretation here is clear: // A constant dataset has no kurtosis. diff --git a/vtkm/worklet/testing/UnitTestDescriptiveStatistics.cxx b/vtkm/worklet/testing/UnitTestDescriptiveStatistics.cxx index 1f6550215..cf5c06f51 100644 --- a/vtkm/worklet/testing/UnitTestDescriptiveStatistics.cxx +++ b/vtkm/worklet/testing/UnitTestDescriptiveStatistics.cxx @@ -238,6 +238,53 @@ void TestMomentsByKey() } } +void TestEdgeCases() +{ + using StatValueType = vtkm::worklet::DescriptiveStatistics::StatState; + StatValueType state1(42); + StatValueType state2; + + StatValueType result = state1 + state2; + VTKM_TEST_ASSERT(test_equal(result.N(), 1)); + VTKM_TEST_ASSERT(test_equal(result.Min(), 42)); + VTKM_TEST_ASSERT(test_equal(result.Max(), 42)); + VTKM_TEST_ASSERT(test_equal(result.Mean(), 42)); + VTKM_TEST_ASSERT(test_equal(result.SampleVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(result.PopulationVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(result.Skewness(), 0)); + VTKM_TEST_ASSERT(test_equal(result.Kurtosis(), 0)); + + result = state2 + state1; + VTKM_TEST_ASSERT(test_equal(result.N(), 1)); + VTKM_TEST_ASSERT(test_equal(result.Min(), 42)); + VTKM_TEST_ASSERT(test_equal(result.Max(), 42)); + VTKM_TEST_ASSERT(test_equal(result.Mean(), 42)); + VTKM_TEST_ASSERT(test_equal(result.SampleVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(result.PopulationVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(result.Skewness(), 0)); + VTKM_TEST_ASSERT(test_equal(result.Kurtosis(), 0)); + + StatValueType empty; + VTKM_TEST_ASSERT(test_equal(empty.N(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Min(), std::numeric_limits::max())); + VTKM_TEST_ASSERT(test_equal(empty.Max(), std::numeric_limits::lowest())); + VTKM_TEST_ASSERT(test_equal(empty.Mean(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.SampleVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.PopulationVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Skewness(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Kurtosis(), 0)); + + result = empty + empty; + VTKM_TEST_ASSERT(test_equal(empty.N(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Min(), std::numeric_limits::max())); + VTKM_TEST_ASSERT(test_equal(empty.Max(), std::numeric_limits::lowest())); + VTKM_TEST_ASSERT(test_equal(empty.Mean(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.SampleVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.PopulationVariance(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Skewness(), 0)); + VTKM_TEST_ASSERT(test_equal(empty.Kurtosis(), 0)); +} + void TestDescriptiveStatistics() { TestSingle(); @@ -249,6 +296,7 @@ void TestDescriptiveStatistics() TestMeanProperties(); TestVarianceProperty(); TestMomentsByKey(); + TestEdgeCases(); } int UnitTestDescriptiveStatistics(int argc, char* argv[])