From 9ed11540f11b07479580ad1e9e76bc2a875e3072 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Wed, 17 May 2023 12:38:43 -0600 Subject: [PATCH 01/38] cleanup Camera --- vtkm/rendering/Camera.h | 1 + vtkm/rendering/MapperVolume.cxx | 4 +- vtkm/rendering/raytracing/Camera.cxx | 151 ++++++++-------------- vtkm/rendering/raytracing/Camera.h | 63 ++++----- vtkm/rendering/raytracing/RayOperations.h | 52 ++++---- 5 files changed, 101 insertions(+), 170 deletions(-) diff --git a/vtkm/rendering/Camera.h b/vtkm/rendering/Camera.h index 2e8113db0..b9ecf50fc 100644 --- a/vtkm/rendering/Camera.h +++ b/vtkm/rendering/Camera.h @@ -96,6 +96,7 @@ public: { TwoD, ThreeD, + Three3DPara, }; VTKM_CONT diff --git a/vtkm/rendering/MapperVolume.cxx b/vtkm/rendering/MapperVolume.cxx index bd7ea0421..303b39944 100644 --- a/vtkm/rendering/MapperVolume.cxx +++ b/vtkm/rendering/MapperVolume.cxx @@ -98,13 +98,11 @@ void MapperVolume::RenderCells(const vtkm::cont::UnknownCellSet& cellset, vtkm::rendering::raytracing::VolumeRendererStructured tracer; vtkm::rendering::raytracing::Camera rayCamera; - vtkm::rendering::raytracing::Ray rays; - vtkm::Int32 width = (vtkm::Int32)this->Internals->Canvas->GetWidth(); vtkm::Int32 height = (vtkm::Int32)this->Internals->Canvas->GetHeight(); - rayCamera.SetParameters(camera, width, height); + vtkm::rendering::raytracing::Ray rays; rayCamera.CreateRays(rays, coords.GetBounds()); rays.Buffers.at(0).InitConst(0.f); raytracing::RayOperations::MapCanvasToRays(rays, camera, *this->Internals->Canvas); diff --git a/vtkm/rendering/raytracing/Camera.cxx b/vtkm/rendering/raytracing/Camera.cxx index 83d2e229d..7b1274d35 100644 --- a/vtkm/rendering/raytracing/Camera.cxx +++ b/vtkm/rendering/raytracing/Camera.cxx @@ -20,13 +20,10 @@ #include #include #include -#include #include #include -#include - namespace vtkm { namespace rendering @@ -229,7 +226,7 @@ public: }; // class perspective ray gen jitter -class Camera::Ortho2DRayGen : public vtkm::worklet::WorkletMapField +class Ortho2DRayGen : public vtkm::worklet::WorkletMapField { public: vtkm::Int32 w; @@ -320,7 +317,7 @@ public: }; // class perspective ray gen -class Camera::PerspectiveRayGen : public vtkm::worklet::WorkletMapField +class PerspectiveRayGen : public vtkm::worklet::WorkletMapField { public: vtkm::Int32 w; @@ -408,7 +405,6 @@ public: bool Camera::operator==(const Camera& other) const { - if (this->Height != other.Height) return false; if (this->Width != other.Width) @@ -427,68 +423,21 @@ bool Camera::operator==(const Camera& other) const return false; if (this->Zoom != other.Zoom) return false; - if (this->Look[0] != other.Look[0]) + if (this->Look != other.Look) return false; - if (this->Look[1] != other.Look[1]) + if (this->LookAt != other.LookAt) return false; - if (this->Look[2] != other.Look[2]) + if (this->Up != other.Up) return false; - if (this->LookAt[0] != other.LookAt[0]) - return false; - if (this->LookAt[1] != other.LookAt[1]) - return false; - if (this->LookAt[2] != other.LookAt[2]) - return false; - if (this->Up[0] != other.Up[0]) - return false; - if (this->Up[1] != other.Up[1]) - return false; - if (this->Up[2] != other.Up[2]) - return false; - if (this->Position[0] != other.Position[0]) - return false; - if (this->Position[1] != other.Position[1]) - return false; - if (this->Position[2] != other.Position[2]) + if (this->Position != other.Position) return false; return true; } - -VTKM_CONT -Camera::Camera() -{ - this->Height = 500; - this->Width = 500; - this->SubsetWidth = 500; - this->SubsetHeight = 500; - this->SubsetMinX = 0; - this->SubsetMinY = 0; - this->FovY = 30.f; - this->FovX = 30.f; - this->Zoom = 1.f; - this->Look[0] = 0.f; - this->Look[1] = 0.f; - this->Look[2] = -1.f; - this->LookAt[0] = 0.f; - this->LookAt[1] = 0.f; - this->LookAt[2] = -1.f; - this->Up[0] = 0.f; - this->Up[1] = 1.f; - this->Up[2] = 0.f; - this->Position[0] = 0.f; - this->Position[1] = 0.f; - this->Position[2] = 0.f; - this->IsViewDirty = true; -} - -VTKM_CONT -Camera::~Camera() {} - VTKM_CONT void Camera::SetParameters(const vtkm::rendering::Camera& camera, - const vtkm::Int32 width, - const vtkm::Int32 height) + vtkm::Int32 width, + vtkm::Int32 height) { this->SetUp(camera.GetViewUp()); this->SetLookAt(camera.GetLookAt()); @@ -500,7 +449,6 @@ void Camera::SetParameters(const vtkm::rendering::Camera& camera, this->CameraView = camera; } - VTKM_CONT void Camera::SetHeight(const vtkm::Int32& height) { @@ -726,19 +674,19 @@ void Camera::GetPixelData(const vtkm::cont::CoordinateSystem& coords, } VTKM_CONT -void Camera::CreateRays(Ray& rays, vtkm::Bounds bounds) +void Camera::CreateRays(Ray& rays, const vtkm::Bounds& bounds) { CreateRaysImpl(rays, bounds); } VTKM_CONT -void Camera::CreateRays(Ray& rays, vtkm::Bounds bounds) +void Camera::CreateRays(Ray& rays, const vtkm::Bounds& bounds) { CreateRaysImpl(rays, bounds); } template -VTKM_CONT void Camera::CreateRaysImpl(Ray& rays, const vtkm::Bounds boundingBox) +VTKM_CONT void Camera::CreateRaysImpl(Ray& rays, const vtkm::Bounds& boundingBox) { Logger* logger = Logger::GetInstance(); vtkm::cont::Timer createTimer; @@ -748,9 +696,9 @@ VTKM_CONT void Camera::CreateRaysImpl(Ray& rays, const vtkm::Bounds b bool ortho = this->CameraView.GetMode() == vtkm::rendering::Camera::Mode::TwoD; this->UpdateDimensions(rays, boundingBox, ortho); this->WriteSettingsToLog(); + vtkm::cont::Timer timer; timer.Start(); - //Set the origin of the ray back to the camera position Precision infinity; GetInfinity(infinity); @@ -772,40 +720,44 @@ VTKM_CONT void Camera::CreateRaysImpl(Ray& rays, const vtkm::Bounds b //Reset the camera look vector this->Look = this->LookAt - this->Position; vtkm::Normalize(this->Look); + + vtkm::cont::Invoker invoke; if (ortho) { - - vtkm::worklet::DispatcherMapField dispatcher(Ortho2DRayGen(this->Width, - this->Height, - this->Zoom, - this->SubsetWidth, - this->SubsetMinX, - this->SubsetMinY, - this->CameraView)); - dispatcher.Invoke(rays.DirX, - rays.DirY, - rays.DirZ, - rays.OriginX, - rays.OriginY, - rays.OriginZ, - rays.PixelIdx); //X Y Z + invoke(Ortho2DRayGen{ this->Width, + this->Height, + this->Zoom, + this->SubsetWidth, + this->SubsetMinX, + this->SubsetMinY, + this->CameraView }, + rays.DirX, + rays.DirY, + rays.DirZ, + rays.OriginX, + rays.OriginY, + rays.OriginZ, + rays.PixelIdx); } else { //Create the ray direction - vtkm::worklet::DispatcherMapField dispatcher( - PerspectiveRayGen(this->Width, - this->Height, - this->FovX, - this->FovY, - this->Look, - this->Up, - this->Zoom, - this->SubsetWidth, - this->SubsetMinX, - this->SubsetMinY)); - dispatcher.Invoke(rays.DirX, rays.DirY, rays.DirZ, rays.PixelIdx); //X Y Z + invoke(PerspectiveRayGen{ this->Width, + this->Height, + this->FovX, + this->FovY, + this->Look, + this->Up, + this->Zoom, + this->SubsetWidth, + this->SubsetMinX, + this->SubsetMinY }, + rays.DirX, + rays.DirY, + rays.DirZ, + rays.PixelIdx); + //Set the origin of the ray back to the camera position vtkm::cont::ArrayHandleConstant posX(this->Position[0], rays.NumRays); vtkm::cont::Algorithm::Copy(posX, rays.OriginX); @@ -934,11 +886,10 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, if (imageSubsetModeOn && !ortho2D) { //Create a transform matrix using the rendering::camera class - vtkm::rendering::Camera camera = this->CameraView; - camera.SetFieldOfView(this->GetFieldOfView()); - camera.SetLookAt(this->GetLookAt()); - camera.SetPosition(this->GetPosition()); - camera.SetViewUp(this->GetUp()); + this->CameraView.SetFieldOfView(this->GetFieldOfView()); + this->CameraView.SetLookAt(this->GetLookAt()); + this->CameraView.SetPosition(this->GetPosition()); + this->CameraView.SetViewUp(this->GetUp()); // // Just create come clipping range, we ignore the zmax value in subsetting // @@ -947,7 +898,8 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, vtkm::Max(boundingBox.Y.Max - boundingBox.Y.Min, boundingBox.Z.Max - boundingBox.Z.Min)); maxDim *= 100; - camera.SetClippingRange(.0001, maxDim); + this->CameraView.SetClippingRange(.0001, maxDim); + //Update our ViewProjection matrix this->ViewProjectionMat = vtkm::MatrixMultiply(this->CameraView.CreateProjectionMatrix(this->Width, this->Height), @@ -983,8 +935,7 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, // resize rays and buffers if (rays.NumRays != SubsetWidth * SubsetHeight) { - RayOperations::Resize( - rays, this->SubsetHeight * this->SubsetWidth, vtkm::cont::DeviceAdapterTagSerial()); + RayOperations::Resize(rays, this->SubsetHeight * this->SubsetWidth); } } @@ -1001,7 +952,7 @@ void Camera::CreateDebugRay(vtkm::Vec2i_32 pixel, Ray& rays) template void Camera::CreateDebugRayImp(vtkm::Vec2i_32 pixel, Ray& rays) { - RayOperations::Resize(rays, 1, vtkm::cont::DeviceAdapterTagSerial()); + RayOperations::Resize(rays, 1); vtkm::Int32 pixelIndex = this->Width * (this->Height - pixel[1]) + pixel[0]; rays.PixelIdx.WritePortal().Set(0, pixelIndex); rays.OriginX.WritePortal().Set(0, this->Position[0]); diff --git a/vtkm/rendering/raytracing/Camera.h b/vtkm/rendering/raytracing/Camera.h index d4a457a19..5836e185f 100644 --- a/vtkm/rendering/raytracing/Camera.h +++ b/vtkm/rendering/raytracing/Camera.h @@ -12,7 +12,6 @@ #include #include -#include #include namespace vtkm @@ -24,55 +23,35 @@ namespace raytracing class VTKM_RENDERING_EXPORT Camera { - private: - struct PixelDataFunctor; - vtkm::Int32 Height; - vtkm::Int32 Width; - vtkm::Int32 SubsetWidth; - vtkm::Int32 SubsetHeight; - vtkm::Int32 SubsetMinX; - vtkm::Int32 SubsetMinY; - vtkm::Float32 FovX; - vtkm::Float32 FovY; - vtkm::Float32 Zoom; - bool IsViewDirty; + vtkm::Int32 Height = 500; + vtkm::Int32 Width = 500; + vtkm::Int32 SubsetWidth = 500; + vtkm::Int32 SubsetHeight = 500; + vtkm::Int32 SubsetMinX = 0; + vtkm::Int32 SubsetMinY = 0; + vtkm::Float32 FovX = 30.f; + vtkm::Float32 FovY = 30.f; + vtkm::Float32 Zoom = 1.f; + bool IsViewDirty = true; - vtkm::Vec3f_32 Look; - vtkm::Vec3f_32 Up; - vtkm::Vec3f_32 LookAt; - vtkm::Vec3f_32 Position; + vtkm::Vec3f_32 Look{ 0.f, 0.f, -1.f }; + vtkm::Vec3f_32 Up{ 0.f, 1.f, 0.f }; + vtkm::Vec3f_32 LookAt{ 0.f, 0.f, -1.f }; + vtkm::Vec3f_32 Position{ 0.f, 0.f, 0.f }; vtkm::rendering::Camera CameraView; vtkm::Matrix ViewProjectionMat; public: VTKM_CONT - Camera(); - - VTKM_CONT - ~Camera(); - - // cuda does not compile if this is private - class PerspectiveRayGen; - class Ortho2DRayGen; - std::string ToString(); VTKM_CONT - void SetParameters(const vtkm::rendering::Camera& camera, - const vtkm::Int32 width, - const vtkm::Int32 height); - - VTKM_CONT - void SetParameters(const vtkm::rendering::Camera& camera, - vtkm::rendering::CanvasRayTracer& canvas); + void SetParameters(const vtkm::rendering::Camera& camera, vtkm::Int32 width, vtkm::Int32 height); VTKM_CONT void SetHeight(const vtkm::Int32& height); - VTKM_CONT - void WriteSettingsToLog(); - VTKM_CONT vtkm::Int32 GetHeight() const; @@ -125,10 +104,10 @@ public: bool GetIsViewDirty() const; VTKM_CONT - void CreateRays(Ray& rays, vtkm::Bounds bounds); + void CreateRays(Ray& rays, const vtkm::Bounds& bounds); VTKM_CONT - void CreateRays(Ray& rays, vtkm::Bounds bounds); + void CreateRays(Ray& rays, const vtkm::Bounds& bounds); VTKM_CONT void GetPixelData(const vtkm::cont::CoordinateSystem& coords, @@ -136,7 +115,7 @@ public: vtkm::Float32& aveRayDistance); template - VTKM_CONT void CreateRaysImpl(Ray& rays, const vtkm::Bounds boundingBox); + VTKM_CONT void CreateRaysImpl(Ray& rays, const vtkm::Bounds& boundingBox); void CreateDebugRay(vtkm::Vec2i_32 pixel, Ray& rays); @@ -146,10 +125,14 @@ public: private: template - void CreateDebugRayImp(vtkm::Vec2i_32 pixel, Ray& rays); + VTKM_CONT void CreateDebugRayImp(vtkm::Vec2i_32 pixel, Ray& rays); + VTKM_CONT void FindSubset(const vtkm::Bounds& bounds); + VTKM_CONT + void WriteSettingsToLog(); + template VTKM_CONT void UpdateDimensions(Ray& rays, const vtkm::Bounds& boundingBox, diff --git a/vtkm/rendering/raytracing/RayOperations.h b/vtkm/rendering/raytracing/RayOperations.h index 5275b441d..0435e28a8 100644 --- a/vtkm/rendering/raytracing/RayOperations.h +++ b/vtkm/rendering/raytracing/RayOperations.h @@ -285,48 +285,46 @@ public: return masks; } - template - static void Resize(Ray& rays, const vtkm::Int32 newSize, Device) + template + static void Resize(Ray& rays, const vtkm::Int32 newSize) { if (newSize == rays.NumRays) return; //nothing to do rays.NumRays = newSize; - vtkm::cont::Token token; if (rays.IntersectionDataEnabled) { - rays.IntersectionX.PrepareForOutput(rays.NumRays, Device(), token); - rays.IntersectionY.PrepareForOutput(rays.NumRays, Device(), token); - rays.IntersectionZ.PrepareForOutput(rays.NumRays, Device(), token); - rays.U.PrepareForOutput(rays.NumRays, Device(), token); - rays.V.PrepareForOutput(rays.NumRays, Device(), token); - rays.Scalar.PrepareForOutput(rays.NumRays, Device(), token); + rays.IntersectionX.Allocate(rays.NumRays); + rays.IntersectionY.Allocate(rays.NumRays); + rays.IntersectionZ.Allocate(rays.NumRays); + rays.U.Allocate(rays.NumRays); + rays.V.Allocate(rays.NumRays); + rays.Scalar.Allocate(rays.NumRays); - rays.NormalX.PrepareForOutput(rays.NumRays, Device(), token); - rays.NormalY.PrepareForOutput(rays.NumRays, Device(), token); - rays.NormalZ.PrepareForOutput(rays.NumRays, Device(), token); + rays.NormalX.Allocate(rays.NumRays); + rays.NormalY.Allocate(rays.NumRays); + rays.NormalZ.Allocate(rays.NumRays); } - rays.OriginX.PrepareForOutput(rays.NumRays, Device(), token); - rays.OriginY.PrepareForOutput(rays.NumRays, Device(), token); - rays.OriginZ.PrepareForOutput(rays.NumRays, Device(), token); + rays.OriginX.Allocate(rays.NumRays); + rays.OriginY.Allocate(rays.NumRays); + rays.OriginZ.Allocate(rays.NumRays); - rays.DirX.PrepareForOutput(rays.NumRays, Device(), token); - rays.DirY.PrepareForOutput(rays.NumRays, Device(), token); - rays.DirZ.PrepareForOutput(rays.NumRays, Device(), token); + rays.DirX.Allocate(rays.NumRays); + rays.DirY.Allocate(rays.NumRays); + rays.DirZ.Allocate(rays.NumRays); - rays.Distance.PrepareForOutput(rays.NumRays, Device(), token); - rays.MinDistance.PrepareForOutput(rays.NumRays, Device(), token); - rays.MaxDistance.PrepareForOutput(rays.NumRays, Device(), token); - rays.Status.PrepareForOutput(rays.NumRays, Device(), token); - rays.HitIdx.PrepareForOutput(rays.NumRays, Device(), token); - rays.PixelIdx.PrepareForOutput(rays.NumRays, Device(), token); + rays.Distance.Allocate(rays.NumRays); + rays.MinDistance.Allocate(rays.NumRays); + rays.MaxDistance.Allocate(rays.NumRays); + rays.Status.Allocate(rays.NumRays); + rays.HitIdx.Allocate(rays.NumRays); + rays.PixelIdx.Allocate(rays.NumRays); - const size_t bufferCount = static_cast(rays.Buffers.size()); - for (size_t i = 0; i < bufferCount; ++i) + for (auto& buffer : rays.Buffers) { - rays.Buffers[i].Resize(rays.NumRays, Device()); + buffer.Resize(rays.NumRays); } } From d660a53b8d66a9fcf41efb154a5b1ce02f0d2169 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 18 May 2023 14:45:16 -0600 Subject: [PATCH 02/38] clean up Ray and RayOperator --- vtkm/rendering/raytracing/Ray.h | 155 +++------------------- vtkm/rendering/raytracing/RayOperations.h | 5 +- 2 files changed, 24 insertions(+), 136 deletions(-) diff --git a/vtkm/rendering/raytracing/Ray.h b/vtkm/rendering/raytracing/Ray.h index 82b627ee8..c1de3225e 100644 --- a/vtkm/rendering/raytracing/Ray.h +++ b/vtkm/rendering/raytracing/Ray.h @@ -69,7 +69,6 @@ public: vtkm::cont::ArrayHandle IntersectionY; vtkm::cont::ArrayHandle IntersectionZ; - vtkm::cont::ArrayHandle OriginX; //ray Origin vtkm::cont::ArrayHandle OriginY; vtkm::cont::ArrayHandle OriginZ; @@ -117,40 +116,26 @@ public: DebugHeight = -1; } - - struct EnableIntersectionDataFunctor - { - template - VTKM_CONT bool operator()(Device, Ray* self) - { - VTKM_IS_DEVICE_ADAPTER_TAG(Device); - self->EnableIntersectionData(Device()); - return true; - } - }; - - void EnableIntersectionData() { vtkm::cont::TryExecute(EnableIntersectionDataFunctor(), this); } - - template - void EnableIntersectionData(Device) + void EnableIntersectionData() { if (IntersectionDataEnabled) { return; } - vtkm::cont::Token token; IntersectionDataEnabled = true; - IntersectionX.PrepareForOutput(NumRays, Device(), token); - IntersectionY.PrepareForOutput(NumRays, Device(), token); - IntersectionZ.PrepareForOutput(NumRays, Device(), token); - U.PrepareForOutput(NumRays, Device(), token); - V.PrepareForOutput(NumRays, Device(), token); - Scalar.PrepareForOutput(NumRays, Device(), token); - NormalX.PrepareForOutput(NumRays, Device(), token); - NormalY.PrepareForOutput(NumRays, Device(), token); - NormalZ.PrepareForOutput(NumRays, Device(), token); + IntersectionX.Allocate(NumRays); + IntersectionY.Allocate(NumRays); + IntersectionZ.Allocate(NumRays); + + U.Allocate(NumRays); + V.Allocate(NumRays); + Scalar.Allocate(NumRays); + + NormalX.Allocate(NumRays); + NormalY.Allocate(NumRays); + NormalZ.Allocate(NumRays); } void DisableIntersectionData() @@ -173,90 +158,9 @@ public: NormalZ.ReleaseResources(); } - template - VTKM_CONT Ray(const vtkm::Int32 size, Device, bool enableIntersectionData = false) - { - NumRays = size; - IntersectionDataEnabled = enableIntersectionData; - - ChannelBuffer buffer; - this->Buffers.push_back(buffer); - - DebugWidth = -1; - DebugHeight = -1; - - this->Resize(size, Device()); - } - - struct ResizeFunctor - { - template - VTKM_CONT bool operator()(Device, Ray* self, const vtkm::Int32 size) - { - VTKM_IS_DEVICE_ADAPTER_TAG(Device); - self->Resize(size, Device()); - return true; - } - }; - - VTKM_CONT void Resize(const vtkm::Int32 size) { vtkm::cont::TryExecute(ResizeFunctor(), size); } - - template - VTKM_CONT void Resize(const vtkm::Int32 size, Device) - { - NumRays = size; - vtkm::cont::Token token; - - if (IntersectionDataEnabled) - { - IntersectionX.PrepareForOutput(NumRays, Device(), token); - IntersectionY.PrepareForOutput(NumRays, Device(), token); - IntersectionZ.PrepareForOutput(NumRays, Device(), token); - - U.PrepareForOutput(NumRays, Device(), token); - V.PrepareForOutput(NumRays, Device(), token); - - Scalar.PrepareForOutput(NumRays, Device(), token); - - NormalX.PrepareForOutput(NumRays, Device(), token); - NormalY.PrepareForOutput(NumRays, Device(), token); - NormalZ.PrepareForOutput(NumRays, Device(), token); - } - - OriginX.PrepareForOutput(NumRays, Device(), token); - OriginY.PrepareForOutput(NumRays, Device(), token); - OriginZ.PrepareForOutput(NumRays, Device(), token); - - DirX.PrepareForOutput(NumRays, Device(), token); - DirY.PrepareForOutput(NumRays, Device(), token); - DirZ.PrepareForOutput(NumRays, Device(), token); - - Distance.PrepareForOutput(NumRays, Device(), token); - - MinDistance.PrepareForOutput(NumRays, Device(), token); - MaxDistance.PrepareForOutput(NumRays, Device(), token); - Status.PrepareForOutput(NumRays, Device(), token); - - HitIdx.PrepareForOutput(NumRays, Device(), token); - PixelIdx.PrepareForOutput(NumRays, Device(), token); - - Intersection = - vtkm::cont::make_ArrayHandleCompositeVector(IntersectionX, IntersectionY, IntersectionZ); - Normal = vtkm::cont::make_ArrayHandleCompositeVector(NormalX, NormalY, NormalZ); - Origin = vtkm::cont::make_ArrayHandleCompositeVector(OriginX, OriginY, OriginZ); - Dir = vtkm::cont::make_ArrayHandleCompositeVector(DirX, DirY, DirZ); - - const size_t numBuffers = this->Buffers.size(); - for (size_t i = 0; i < numBuffers; ++i) - { - this->Buffers[i].Resize(NumRays, Device()); - } - } - VTKM_CONT void AddBuffer(const vtkm::Int32 numChannels, const std::string name) { - ChannelBuffer buffer(numChannels, this->NumRays); buffer.SetName(name); this->Buffers.push_back(buffer); @@ -265,41 +169,24 @@ public: VTKM_CONT bool HasBuffer(const std::string name) { - size_t numBuffers = this->Buffers.size(); - bool found = false; - for (size_t i = 0; i < numBuffers; ++i) + for (const auto& buffer : this->Buffers) { - if (this->Buffers[i].GetName() == name) - { - found = true; - break; - } + if (buffer.GetName() == name) + return true; } - return found; + return false; } VTKM_CONT ChannelBuffer& GetBuffer(const std::string name) { - const size_t numBuffers = this->Buffers.size(); - bool found = false; - size_t index = 0; - for (size_t i = 0; i < numBuffers; ++i) + for (auto&& buffer : this->Buffers) { - if (this->Buffers[i].GetName() == name) - { - found = true; - index = i; - } - } - if (found) - { - return this->Buffers.at(index); - } - else - { - throw vtkm::cont::ErrorBadValue("No channel buffer with requested name: " + name); + if (buffer.GetName() == name) + return buffer; } + + throw vtkm::cont::ErrorBadValue("No channel buffer with requested name: " + name); } void PrintRay(vtkm::Id pixelId) diff --git a/vtkm/rendering/raytracing/RayOperations.h b/vtkm/rendering/raytracing/RayOperations.h index 0435e28a8..9464ed97e 100644 --- a/vtkm/rendering/raytracing/RayOperations.h +++ b/vtkm/rendering/raytracing/RayOperations.h @@ -277,7 +277,7 @@ public: rays.NumRays = rays.Status.ReadPortal().GetNumberOfValues(); - const size_t bufferCount = static_cast(rays.Buffers.size()); + const auto bufferCount = static_cast(rays.Buffers.size()); for (size_t i = 0; i < bufferCount; ++i) { ChannelBufferOperations::Compact(rays.Buffers[i], masks, rays.NumRays); @@ -298,6 +298,7 @@ public: rays.IntersectionX.Allocate(rays.NumRays); rays.IntersectionY.Allocate(rays.NumRays); rays.IntersectionZ.Allocate(rays.NumRays); + rays.U.Allocate(rays.NumRays); rays.V.Allocate(rays.NumRays); rays.Scalar.Allocate(rays.NumRays); @@ -322,7 +323,7 @@ public: rays.HitIdx.Allocate(rays.NumRays); rays.PixelIdx.Allocate(rays.NumRays); - for (auto& buffer : rays.Buffers) + for (auto&& buffer : rays.Buffers) { buffer.Resize(rays.NumRays); } From 2631e5561fa70aac09970fac5b0f849740c6f867 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 24 May 2023 15:01:48 -0600 Subject: [PATCH 03/38] Split up the particle advection/streamline test The test for particle advection filters was one large test that tested 3 versions --- advection, streamlines, and pathlines --- with each tested for a variety of conditions including asynchronous communication, number of blocks, ghost cells, etc. This was causing the test to take a while and sometimes time out. (It would also sometimes seg fault, which I hope is related.) To attempt to fix this problem, break up this test into pieces so that each piece takes a shorter amount of time. Because these tests share most of their implementation (which is why they were grouped together in the first place) the common code is placed in a source file of shared implementation. To support this I also added a way to mark a source file to `vtkm_unit_tests` as a source file that does not contain its own test. Normally you would just compile all of the tests together, select each with command line arguments, and use duplicate `add_tests` for each argument. But that is not how `vtkm_unit_tests` works, and it would be too hard to make that change. --- CMake/testing/VTKmTestWrappers.cmake | 31 +- vtkm/filter/flow/testing/CMakeLists.txt | 17 +- vtkm/filter/flow/testing/TestingFlow.cxx | 313 +++++++++++++++++ vtkm/filter/flow/testing/TestingFlow.h | 82 +++++ .../UnitTestAdvectionAsynchronousMPI.cxx | 59 ++++ .../UnitTestAdvectionSynchronousMPI.cxx | 59 ++++ .../UnitTestPathlineAsynchronousMPI.cxx | 59 ++++ .../UnitTestPathlineSynchronousMPI.cxx | 59 ++++ ...erMPI.cxx => UnitTestStreamlineAMRMPI.cxx} | 314 +----------------- .../UnitTestStreamlineAsynchronousMPI.cxx | 59 ++++ .../UnitTestStreamlineSynchronousMPI.cxx | 59 ++++ 11 files changed, 803 insertions(+), 308 deletions(-) create mode 100644 vtkm/filter/flow/testing/TestingFlow.cxx create mode 100644 vtkm/filter/flow/testing/TestingFlow.h create mode 100644 vtkm/filter/flow/testing/UnitTestAdvectionAsynchronousMPI.cxx create mode 100644 vtkm/filter/flow/testing/UnitTestAdvectionSynchronousMPI.cxx create mode 100644 vtkm/filter/flow/testing/UnitTestPathlineAsynchronousMPI.cxx create mode 100644 vtkm/filter/flow/testing/UnitTestPathlineSynchronousMPI.cxx rename vtkm/filter/flow/testing/{UnitTestStreamlineFilterMPI.cxx => UnitTestStreamlineAMRMPI.cxx} (52%) create mode 100644 vtkm/filter/flow/testing/UnitTestStreamlineAsynchronousMPI.cxx create mode 100644 vtkm/filter/flow/testing/UnitTestStreamlineSynchronousMPI.cxx diff --git a/CMake/testing/VTKmTestWrappers.cmake b/CMake/testing/VTKmTestWrappers.cmake index 536f0cf3f..6c64f79cb 100644 --- a/CMake/testing/VTKmTestWrappers.cmake +++ b/CMake/testing/VTKmTestWrappers.cmake @@ -39,11 +39,24 @@ function(_vtkm_create_test_executable set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN "") endif() - #the creation of the test source list needs to occur before the labeling as + #The creation of the test source list needs to occur before the labeling as #cuda. This is so that we get the correctly named entry points generated - create_test_sourcelist(test_sources ${prog}.cxx ${sources} ${device_sources} ${extraArgs}) + #Also, although we usually assume that each source file is a test, we need + #to check for the `NOT_A_TEST` property for support code that should be + #compiled with the executable but is not a test itself. + set(test_sources) + set(extra_sources) + foreach(src IN LISTS sources device_sources) + get_source_file_property(not_a_test ${src} NOT_A_TEST) + if (not_a_test) + list(APPEND extra_sources ${src}) + else() + list(APPEND test_sources ${src}) + endif() + endforeach() + create_test_sourcelist(test_sources ${prog}.cxx ${test_sources} ${extraArgs}) - add_executable(${prog} ${test_sources}) + add_executable(${prog} ${test_sources} ${extra_sources}) vtkm_add_drop_unused_function_flags(${prog}) target_compile_definitions(${prog} PRIVATE ${defines}) @@ -91,6 +104,14 @@ endfunction() # function with the same name as the source file. For example, if SOURCES # contains `UnitTestFoo.cxx`, then `UnitTestFoo.cxx` should contain a # function named `UnitTestFoo`. A test with this name is also added to ctest. +# If you want to add a source file that should not be treated as a test, then +# you can attach the `NOT_A_TEST` property to those files (using +# `set_source_files_properties`), and that file will be added to the test +# executable without adding an associated test. +# +# DEVICE_SOURCES: The same as SOURCES except that each file will be compiled +# with the device compiler. You can use both SOURCES and DEVICE_SOURCES +# together to specify which compiler to use for each file. # # LIBRARIES: Extra libraries that this set of tests need to link to. # @@ -296,6 +317,10 @@ vtkm_unit_tests but not in its test dependencies. Add test dependencies to \ endif() foreach (test ${VTKm_UT_SOURCES} ${VTKm_UT_DEVICE_SOURCES}) + get_source_file_property(not_a_test ${test} NOT_A_TEST) + if (not_a_test) + continue() + endif() get_filename_component(tname ${test} NAME_WE) if(VTKm_UT_MPI) if (VTKm_ENABLE_MPI) diff --git a/vtkm/filter/flow/testing/CMakeLists.txt b/vtkm/filter/flow/testing/CMakeLists.txt index 3c7126ca4..b8bbaa7d2 100644 --- a/vtkm/filter/flow/testing/CMakeLists.txt +++ b/vtkm/filter/flow/testing/CMakeLists.txt @@ -37,12 +37,23 @@ vtkm_unit_tests( #if MPI is enabled. if (VTKm_ENABLE_MPI) set(mpi_unit_tests + UnitTestAdvectionAsynchronousMPI.cxx + UnitTestAdvectionSynchronousMPI.cxx UnitTestParticleMessengerMPI.cxx - UnitTestStreamlineFilterMPI.cxx - ) + UnitTestPathlineAsynchronousMPI.cxx + UnitTestPathlineSynchronousMPI.cxx + UnitTestStreamlineAMRMPI.cxx + UnitTestStreamlineAsynchronousMPI.cxx + UnitTestStreamlineSynchronousMPI.cxx + ) + set(mpi_helpers + TestingFlow.cxx + TestingFlow.h + ) + set_source_files_properties(${mpi_helpers} PROPERTIES NOT_A_TEST TRUE) vtkm_unit_tests( MPI - DEVICE_SOURCES ${mpi_unit_tests} + SOURCES ${mpi_unit_tests} ${mpi_helpers} USE_VTKM_JOB_POOL ) endif() diff --git a/vtkm/filter/flow/testing/TestingFlow.cxx b/vtkm/filter/flow/testing/TestingFlow.cxx new file mode 100644 index 000000000..6ece724d0 --- /dev/null +++ b/vtkm/filter/flow/testing/TestingFlow.cxx @@ -0,0 +1,313 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include +#include +#include +#include +#include +#include +#include + +vtkm::cont::ArrayHandle CreateConstantVectorField(vtkm::Id num, const vtkm::Vec3f& vec) +{ + vtkm::cont::ArrayHandleConstant vecConst; + vecConst = vtkm::cont::make_ArrayHandleConstant(vec, num); + + vtkm::cont::ArrayHandle vecField; + vtkm::cont::ArrayCopy(vecConst, vecField); + return vecField; +} + +void AddVectorFields(vtkm::cont::PartitionedDataSet& pds, + const std::string& fieldName, + const vtkm::Vec3f& vec) +{ + for (auto& ds : pds) + ds.AddPointField(fieldName, CreateConstantVectorField(ds.GetNumberOfPoints(), vec)); +} + +std::vector CreateAllDataSetBounds(vtkm::Id nPerRank, bool useGhost) +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + vtkm::Id totNumBlocks = nPerRank * comm.size(); + vtkm::Id numDims = 5; + + vtkm::FloatDefault x0 = 0; + vtkm::FloatDefault x1 = x0 + static_cast(numDims - 1); + vtkm::FloatDefault dx = x1 - x0; + vtkm::FloatDefault y0 = 0, y1 = numDims - 1, z0 = 0, z1 = numDims - 1; + + if (useGhost) + { + numDims = numDims + 2; //add 1 extra on each side + x0 = x0 - 1; + x1 = x1 + 1; + dx = x1 - x0 - 2; + y0 = y0 - 1; + y1 = y1 + 1; + z0 = z0 - 1; + z1 = z1 + 1; + } + + //Create ALL of the blocks. + std::vector bounds; + for (vtkm::Id i = 0; i < totNumBlocks; i++) + { + bounds.push_back(vtkm::Bounds(x0, x1, y0, y1, z0, z1)); + x0 += dx; + x1 += dx; + } + + const vtkm::Id3 dims(numDims, numDims, numDims); + auto allPDS = vtkm::worklet::testing::CreateAllDataSets(bounds, dims, useGhost); + + return allPDS; +} + +std::vector ExtractMaxXRanges(const vtkm::cont::PartitionedDataSet& pds, bool useGhost) +{ + std::vector xMaxRanges; + for (const auto& ds : pds.GetPartitions()) + { + auto bounds = ds.GetCoordinateSystem().GetBounds(); + auto xMax = bounds.X.Max; + if (useGhost) + xMax = xMax - 1; + xMaxRanges.push_back(vtkm::Range(xMax, xMax + static_cast(.5))); + } + + return xMaxRanges; +} + +void ValidateOutput(const vtkm::cont::DataSet& out, + vtkm::Id numSeeds, + const vtkm::Range& xMaxRange, + FilterType fType, + bool checkEndPoint, + bool blockDuplication) +{ + //Validate the result is correct. + VTKM_TEST_ASSERT(out.GetNumberOfCoordinateSystems() == 1, + "Wrong number of coordinate systems in the output dataset"); + + vtkm::cont::UnknownCellSet dcells = out.GetCellSet(); + vtkm::Id numCells = out.GetNumberOfCells(); + + if (!blockDuplication) + VTKM_TEST_ASSERT(numCells == numSeeds, "Wrong number of cells"); + + auto coords = out.GetCoordinateSystem().GetDataAsMultiplexer(); + auto ptPortal = coords.ReadPortal(); + + if (fType == STREAMLINE || fType == PATHLINE) + { + vtkm::cont::CellSetExplicit<> explicitCells; + VTKM_TEST_ASSERT(dcells.IsType>(), "Wrong cell type."); + explicitCells = dcells.AsCellSet>(); + for (vtkm::Id j = 0; j < numCells; j++) + { + vtkm::cont::ArrayHandle indices; + explicitCells.GetIndices(j, indices); + vtkm::Id nPts = indices.GetNumberOfValues(); + auto iPortal = indices.ReadPortal(); + vtkm::Vec3f lastPt = ptPortal.Get(iPortal.Get(nPts - 1)); + if (checkEndPoint) + VTKM_TEST_ASSERT(xMaxRange.Contains(lastPt[0]), "Wrong end point for seed"); + } + } + else if (fType == PARTICLE_ADVECTION) + { + if (!blockDuplication) + VTKM_TEST_ASSERT(out.GetNumberOfPoints() == numSeeds, "Wrong number of coordinates"); + if (checkEndPoint) + { + for (vtkm::Id i = 0; i < numCells; i++) + VTKM_TEST_ASSERT(xMaxRange.Contains(ptPortal.Get(i)[0]), "Wrong end point for seed"); + } + } +} + +void TestPartitionedDataSet(vtkm::Id nPerRank, + bool useGhost, + FilterType fType, + bool useThreaded, + bool useAsyncComm, + bool useBlockIds, + bool duplicateBlocks) +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + if (comm.rank() == 0) + { + switch (fType) + { + case PARTICLE_ADVECTION: + std::cout << "Particle advection"; + break; + case STREAMLINE: + std::cout << "Streamline"; + break; + case PATHLINE: + std::cout << "Pathline"; + break; + } + std::cout << " blocksPerRank= " << nPerRank; + if (useGhost) + std::cout << " - using ghost cells"; + if (useThreaded) + std::cout << " - using threaded"; + if (useAsyncComm) + std::cout << " - usingAsyncComm"; + else + std::cout << " - usingSyncComm"; + + if (useBlockIds) + std::cout << " - using block IDs"; + if (duplicateBlocks) + std::cout << " - with duplicate blocks"; + std::cout << " - on a partitioned data set" << std::endl; + } + + std::vector blockIds; + //Uniform assignment. + for (vtkm::Id i = 0; i < nPerRank; i++) + blockIds.push_back(comm.rank() * nPerRank + i); + + //For block duplication, give everyone the 2nd to last block. + //We want to keep the last block on the last rank for validation. + if (duplicateBlocks && blockIds.size() > 1) + { + vtkm::Id totNumBlocks = comm.size() * nPerRank; + vtkm::Id dupBlock = totNumBlocks - 2; + for (int r = 0; r < comm.size(); r++) + { + if (std::find(blockIds.begin(), blockIds.end(), dupBlock) == blockIds.end()) + blockIds.push_back(dupBlock); + } + } + + std::vector allPDS, allPDS2; + allPDS = CreateAllDataSetBounds(nPerRank, useGhost); + allPDS2 = CreateAllDataSetBounds(nPerRank, useGhost); + auto xMaxRanges = ExtractMaxXRanges(allPDS[0], useGhost); + + vtkm::FloatDefault time0 = 0; + vtkm::FloatDefault time1 = xMaxRanges[xMaxRanges.size() - 1].Max; + + vtkm::Vec3f vecX(1, 0, 0); + std::string fieldName = "vec"; + vtkm::FloatDefault stepSize = 0.1f; + vtkm::Id numSteps = 100000; + for (std::size_t n = 0; n < allPDS.size(); n++) + { + vtkm::cont::PartitionedDataSet pds; + for (const auto& bid : blockIds) + pds.AppendPartition(allPDS[n].GetPartition(bid)); + AddVectorFields(pds, fieldName, vecX); + + vtkm::cont::ArrayHandle seedArray; + seedArray = vtkm::cont::make_ArrayHandle({ vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0), + vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1) }); + vtkm::Id numSeeds = seedArray.GetNumberOfValues(); + + if (fType == STREAMLINE) + { + vtkm::filter::flow::Streamline streamline; + SetFilter(streamline, + stepSize, + numSteps, + fieldName, + seedArray, + useThreaded, + useAsyncComm, + useBlockIds, + blockIds); + auto out = streamline.Execute(pds); + + vtkm::Id numOutputs = out.GetNumberOfPartitions(); + bool checkEnds = numOutputs == static_cast(blockIds.size()); + for (vtkm::Id i = 0; i < numOutputs; i++) + { + ValidateOutput(out.GetPartition(i), + numSeeds, + xMaxRanges[blockIds[i]], + fType, + checkEnds, + duplicateBlocks); + } + } + else if (fType == PARTICLE_ADVECTION) + { + vtkm::filter::flow::ParticleAdvection particleAdvection; + SetFilter(particleAdvection, + stepSize, + numSteps, + fieldName, + seedArray, + useThreaded, + useAsyncComm, + useBlockIds, + blockIds); + + auto out = particleAdvection.Execute(pds); + + //Particles end up in last rank. + if (comm.rank() == comm.size() - 1) + { + bool checkEnds = out.GetNumberOfPartitions() == static_cast(blockIds.size()); + VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 1, "Wrong number of partitions in output"); + ValidateOutput(out.GetPartition(0), + numSeeds, + xMaxRanges[xMaxRanges.size() - 1], + fType, + checkEnds, + duplicateBlocks); + } + else + VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 0, "Wrong number of partitions in output"); + } + else if (fType == PATHLINE) + { + vtkm::cont::PartitionedDataSet pds2; + for (const auto& bid : blockIds) + pds2.AppendPartition(allPDS2[n].GetPartition(bid)); + AddVectorFields(pds2, fieldName, vecX); + + vtkm::filter::flow::Pathline pathline; + SetFilter(pathline, + stepSize, + numSteps, + fieldName, + seedArray, + useThreaded, + useAsyncComm, + useBlockIds, + blockIds); + + pathline.SetPreviousTime(time0); + pathline.SetNextTime(time1); + pathline.SetNextDataSet(pds2); + + auto out = pathline.Execute(pds); + vtkm::Id numOutputs = out.GetNumberOfPartitions(); + bool checkEnds = numOutputs == static_cast(blockIds.size()); + for (vtkm::Id i = 0; i < numOutputs; i++) + ValidateOutput(out.GetPartition(i), + numSeeds, + xMaxRanges[blockIds[i]], + fType, + checkEnds, + duplicateBlocks); + } + } +} diff --git a/vtkm/filter/flow/testing/TestingFlow.h b/vtkm/filter/flow/testing/TestingFlow.h new file mode 100644 index 000000000..016b7db79 --- /dev/null +++ b/vtkm/filter/flow/testing/TestingFlow.h @@ -0,0 +1,82 @@ +//============================================================================ +// 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_flow_testing_TestingFlow_h +#define vtk_m_filter_flow_testing_TestingFlow_h + +#include + +#include +#include +#include + +#include + +enum FilterType +{ + PARTICLE_ADVECTION, + STREAMLINE, + PATHLINE +}; + +vtkm::cont::ArrayHandle CreateConstantVectorField(vtkm::Id num, + const vtkm::Vec3f& vec); + +void AddVectorFields(vtkm::cont::PartitionedDataSet& pds, + const std::string& fieldName, + const vtkm::Vec3f& vec); + +std::vector CreateAllDataSetBounds(vtkm::Id nPerRank, + bool useGhost); + +std::vector ExtractMaxXRanges(const vtkm::cont::PartitionedDataSet& pds, + bool useGhost); + +template +void SetFilter(FilterType& filter, + vtkm::FloatDefault stepSize, + vtkm::Id numSteps, + const std::string& fieldName, + vtkm::cont::ArrayHandle seedArray, + bool useThreaded, + bool useAsyncComm, + bool useBlockIds, + const std::vector& blockIds) +{ + filter.SetStepSize(stepSize); + filter.SetNumberOfSteps(numSteps); + filter.SetSeeds(seedArray); + filter.SetActiveField(fieldName); + filter.SetUseThreadedAlgorithm(useThreaded); + if (useAsyncComm) + filter.SetUseAsynchronousCommunication(); + else + filter.SetUseSynchronousCommunication(); + + if (useBlockIds) + filter.SetBlockIDs(blockIds); +} + +void ValidateOutput(const vtkm::cont::DataSet& out, + vtkm::Id numSeeds, + const vtkm::Range& xMaxRange, + FilterType fType, + bool checkEndPoint, + bool blockDuplication); + +void TestPartitionedDataSet(vtkm::Id nPerRank, + bool useGhost, + FilterType fType, + bool useThreaded, + bool useAsyncComm, + bool useBlockIds, + bool duplicateBlocks); + +#endif // vtk_m_filter_flow_testing_TestingFlow_h diff --git a/vtkm/filter/flow/testing/UnitTestAdvectionAsynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestAdvectionAsynchronousMPI.cxx new file mode 100644 index 000000000..be6439f64 --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestAdvectionAsynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = PARTICLE_ADVECTION; + bool useAsyncComm = true; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestAdvectionAsynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} diff --git a/vtkm/filter/flow/testing/UnitTestAdvectionSynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestAdvectionSynchronousMPI.cxx new file mode 100644 index 000000000..a6363b771 --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestAdvectionSynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = PARTICLE_ADVECTION; + bool useAsyncComm = false; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestAdvectionSynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} diff --git a/vtkm/filter/flow/testing/UnitTestPathlineAsynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestPathlineAsynchronousMPI.cxx new file mode 100644 index 000000000..5eabb9df8 --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestPathlineAsynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = PATHLINE; + bool useAsyncComm = true; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestPathlineAsynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} diff --git a/vtkm/filter/flow/testing/UnitTestPathlineSynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestPathlineSynchronousMPI.cxx new file mode 100644 index 000000000..1fe976c08 --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestPathlineSynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = PATHLINE; + bool useAsyncComm = false; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestPathlineSynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} diff --git a/vtkm/filter/flow/testing/UnitTestStreamlineFilterMPI.cxx b/vtkm/filter/flow/testing/UnitTestStreamlineAMRMPI.cxx similarity index 52% rename from vtkm/filter/flow/testing/UnitTestStreamlineFilterMPI.cxx rename to vtkm/filter/flow/testing/UnitTestStreamlineAMRMPI.cxx index e46edf7b1..32358e25f 100644 --- a/vtkm/filter/flow/testing/UnitTestStreamlineFilterMPI.cxx +++ b/vtkm/filter/flow/testing/UnitTestStreamlineAMRMPI.cxx @@ -45,60 +45,6 @@ void AddVectorFields(vtkm::cont::PartitionedDataSet& pds, ds.AddPointField(fieldName, CreateConstantVectorField(ds.GetNumberOfPoints(), vec)); } -std::vector CreateAllDataSetBounds(vtkm::Id nPerRank, bool useGhost) -{ - auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); - - vtkm::Id totNumBlocks = nPerRank * comm.size(); - vtkm::Id numDims = 5; - - vtkm::FloatDefault x0 = 0; - vtkm::FloatDefault x1 = x0 + static_cast(numDims - 1); - vtkm::FloatDefault dx = x1 - x0; - vtkm::FloatDefault y0 = 0, y1 = numDims - 1, z0 = 0, z1 = numDims - 1; - - if (useGhost) - { - numDims = numDims + 2; //add 1 extra on each side - x0 = x0 - 1; - x1 = x1 + 1; - dx = x1 - x0 - 2; - y0 = y0 - 1; - y1 = y1 + 1; - z0 = z0 - 1; - z1 = z1 + 1; - } - - //Create ALL of the blocks. - std::vector bounds; - for (vtkm::Id i = 0; i < totNumBlocks; i++) - { - bounds.push_back(vtkm::Bounds(x0, x1, y0, y1, z0, z1)); - x0 += dx; - x1 += dx; - } - - const vtkm::Id3 dims(numDims, numDims, numDims); - auto allPDS = vtkm::worklet::testing::CreateAllDataSets(bounds, dims, useGhost); - - return allPDS; -} - -std::vector ExtractMaxXRanges(const vtkm::cont::PartitionedDataSet& pds, bool useGhost) -{ - std::vector xMaxRanges; - for (const auto& ds : pds.GetPartitions()) - { - auto bounds = ds.GetCoordinateSystem().GetBounds(); - auto xMax = bounds.X.Max; - if (useGhost) - xMax = xMax - 1; - xMaxRanges.push_back(vtkm::Range(xMax, xMax + static_cast(.5))); - } - - return xMaxRanges; -} - template void SetFilter(FilterType& filter, vtkm::FloatDefault stepSize, @@ -356,265 +302,29 @@ void TestAMRStreamline(FilterType fType, bool useThreaded, bool useAsyncComm) } } -void ValidateOutput(const vtkm::cont::DataSet& out, - vtkm::Id numSeeds, - const vtkm::Range& xMaxRange, - FilterType fType, - bool checkEndPoint, - bool blockDuplication) -{ - //Validate the result is correct. - VTKM_TEST_ASSERT(out.GetNumberOfCoordinateSystems() == 1, - "Wrong number of coordinate systems in the output dataset"); - - vtkm::cont::UnknownCellSet dcells = out.GetCellSet(); - vtkm::Id numCells = out.GetNumberOfCells(); - - if (!blockDuplication) - VTKM_TEST_ASSERT(numCells == numSeeds, "Wrong number of cells"); - - auto coords = out.GetCoordinateSystem().GetDataAsMultiplexer(); - auto ptPortal = coords.ReadPortal(); - - if (fType == STREAMLINE || fType == PATHLINE) - { - vtkm::cont::CellSetExplicit<> explicitCells; - VTKM_TEST_ASSERT(dcells.IsType>(), "Wrong cell type."); - explicitCells = dcells.AsCellSet>(); - for (vtkm::Id j = 0; j < numCells; j++) - { - vtkm::cont::ArrayHandle indices; - explicitCells.GetIndices(j, indices); - vtkm::Id nPts = indices.GetNumberOfValues(); - auto iPortal = indices.ReadPortal(); - vtkm::Vec3f lastPt = ptPortal.Get(iPortal.Get(nPts - 1)); - if (checkEndPoint) - VTKM_TEST_ASSERT(xMaxRange.Contains(lastPt[0]), "Wrong end point for seed"); - } - } - else if (fType == PARTICLE_ADVECTION) - { - if (!blockDuplication) - VTKM_TEST_ASSERT(out.GetNumberOfPoints() == numSeeds, "Wrong number of coordinates"); - if (checkEndPoint) - { - for (vtkm::Id i = 0; i < numCells; i++) - VTKM_TEST_ASSERT(xMaxRange.Contains(ptPortal.Get(i)[0]), "Wrong end point for seed"); - } - } -} - -void TestPartitionedDataSet(vtkm::Id nPerRank, - bool useGhost, - FilterType fType, - bool useThreaded, - bool useAsyncComm, - bool useBlockIds, - bool duplicateBlocks) +void DoTest() { auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); if (comm.rank() == 0) { - switch (fType) - { - case PARTICLE_ADVECTION: - std::cout << "Particle advection"; - break; - case STREAMLINE: - std::cout << "Streamline"; - break; - case PATHLINE: - std::cout << "Pathline"; - break; - } - std::cout << " blocksPerRank= " << nPerRank; - if (useGhost) - std::cout << " - using ghost cells"; - if (useThreaded) - std::cout << " - using threaded"; - if (useAsyncComm) - std::cout << " - usingAsyncComm"; - else - std::cout << " - usingSyncComm"; - - if (useBlockIds) - std::cout << " - using block IDs"; - if (duplicateBlocks) - std::cout << " - with duplicate blocks"; - std::cout << " - on a partitioned data set" << std::endl; + std::cout << std::endl << "*** TestStreamlineAMRMPI" << std::endl; } - std::vector blockIds; - //Uniform assignment. - for (vtkm::Id i = 0; i < nPerRank; i++) - blockIds.push_back(comm.rank() * nPerRank + i); - - //For block duplication, give everyone the 2nd to last block. - //We want to keep the last block on the last rank for validation. - if (duplicateBlocks && blockIds.size() > 1) + for (auto fType : { PARTICLE_ADVECTION, STREAMLINE, PATHLINE }) { - vtkm::Id totNumBlocks = comm.size() * nPerRank; - vtkm::Id dupBlock = totNumBlocks - 2; - for (int r = 0; r < comm.size(); r++) + for (auto useThreaded : { true, false }) { - if (std::find(blockIds.begin(), blockIds.end(), dupBlock) == blockIds.end()) - blockIds.push_back(dupBlock); - } - } - - std::vector allPDS, allPDS2; - allPDS = CreateAllDataSetBounds(nPerRank, useGhost); - allPDS2 = CreateAllDataSetBounds(nPerRank, useGhost); - auto xMaxRanges = ExtractMaxXRanges(allPDS[0], useGhost); - - vtkm::FloatDefault time0 = 0; - vtkm::FloatDefault time1 = xMaxRanges[xMaxRanges.size() - 1].Max; - - vtkm::Vec3f vecX(1, 0, 0); - std::string fieldName = "vec"; - vtkm::FloatDefault stepSize = 0.1f; - vtkm::Id numSteps = 100000; - for (std::size_t n = 0; n < allPDS.size(); n++) - { - vtkm::cont::PartitionedDataSet pds; - for (const auto& bid : blockIds) - pds.AppendPartition(allPDS[n].GetPartition(bid)); - AddVectorFields(pds, fieldName, vecX); - - vtkm::cont::ArrayHandle seedArray; - seedArray = vtkm::cont::make_ArrayHandle({ vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0), - vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1) }); - vtkm::Id numSeeds = seedArray.GetNumberOfValues(); - - if (fType == STREAMLINE) - { - vtkm::filter::flow::Streamline streamline; - SetFilter(streamline, - stepSize, - numSteps, - fieldName, - seedArray, - useThreaded, - useAsyncComm, - useBlockIds, - blockIds); - auto out = streamline.Execute(pds); - - vtkm::Id numOutputs = out.GetNumberOfPartitions(); - bool checkEnds = numOutputs == static_cast(blockIds.size()); - for (vtkm::Id i = 0; i < numOutputs; i++) + for (auto useAsyncComm : { true, false }) { - ValidateOutput(out.GetPartition(i), - numSeeds, - xMaxRanges[blockIds[i]], - fType, - checkEnds, - duplicateBlocks); - } - } - else if (fType == PARTICLE_ADVECTION) - { - vtkm::filter::flow::ParticleAdvection particleAdvection; - SetFilter(particleAdvection, - stepSize, - numSteps, - fieldName, - seedArray, - useThreaded, - useAsyncComm, - useBlockIds, - blockIds); - - auto out = particleAdvection.Execute(pds); - - //Particles end up in last rank. - if (comm.rank() == comm.size() - 1) - { - bool checkEnds = out.GetNumberOfPartitions() == static_cast(blockIds.size()); - VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 1, "Wrong number of partitions in output"); - ValidateOutput(out.GetPartition(0), - numSeeds, - xMaxRanges[xMaxRanges.size() - 1], - fType, - checkEnds, - duplicateBlocks); - } - else - VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 0, "Wrong number of partitions in output"); - } - else if (fType == PATHLINE) - { - vtkm::cont::PartitionedDataSet pds2; - for (const auto& bid : blockIds) - pds2.AppendPartition(allPDS2[n].GetPartition(bid)); - AddVectorFields(pds2, fieldName, vecX); - - vtkm::filter::flow::Pathline pathline; - SetFilter(pathline, - stepSize, - numSteps, - fieldName, - seedArray, - useThreaded, - useAsyncComm, - useBlockIds, - blockIds); - - pathline.SetPreviousTime(time0); - pathline.SetNextTime(time1); - pathline.SetNextDataSet(pds2); - - auto out = pathline.Execute(pds); - vtkm::Id numOutputs = out.GetNumberOfPartitions(); - bool checkEnds = numOutputs == static_cast(blockIds.size()); - for (vtkm::Id i = 0; i < numOutputs; i++) - ValidateOutput(out.GetPartition(i), - numSeeds, - xMaxRanges[blockIds[i]], - fType, - checkEnds, - duplicateBlocks); - } - } -} - -void TestStreamlineFiltersMPI() -{ - auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); - if (comm.rank() == 0) - std::cout << std::endl << "*** TestStreamlineFiltersMPI" << std::endl; - - std::vector flags = { true, false }; - std::vector filterTypes = { PARTICLE_ADVECTION, STREAMLINE, PATHLINE }; - - for (int n = 1; n < 3; n++) - for (auto useGhost : flags) - for (auto fType : filterTypes) - for (auto useThreaded : flags) - for (auto useAsyncComm : flags) - for (auto useBlockIds : flags) - { - //Run blockIds with and without block duplication. - if (useBlockIds && comm.size() > 1) - { - TestPartitionedDataSet( - n, useGhost, fType, useThreaded, useAsyncComm, useBlockIds, false); - TestPartitionedDataSet( - n, useGhost, fType, useThreaded, useAsyncComm, useBlockIds, true); - } - else - TestPartitionedDataSet( - n, useGhost, fType, useThreaded, useAsyncComm, useBlockIds, false); - } - - for (auto fType : filterTypes) - for (auto useThreaded : flags) - for (auto useAsyncComm : flags) TestAMRStreamline(fType, useThreaded, useAsyncComm); -} + } + } + } } -int UnitTestStreamlineFilterMPI(int argc, char* argv[]) +} // anonymous namespace + +int UnitTestStreamlineAMRMPI(int argc, char* argv[]) { - return vtkm::cont::testing::Testing::Run(TestStreamlineFiltersMPI, argc, argv); + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); } diff --git a/vtkm/filter/flow/testing/UnitTestStreamlineAsynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestStreamlineAsynchronousMPI.cxx new file mode 100644 index 000000000..26fad71aa --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestStreamlineAsynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = STREAMLINE; + bool useAsyncComm = true; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestStreamlineAsynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} diff --git a/vtkm/filter/flow/testing/UnitTestStreamlineSynchronousMPI.cxx b/vtkm/filter/flow/testing/UnitTestStreamlineSynchronousMPI.cxx new file mode 100644 index 000000000..9550c4dc9 --- /dev/null +++ b/vtkm/filter/flow/testing/UnitTestStreamlineSynchronousMPI.cxx @@ -0,0 +1,59 @@ +//============================================================================ +// 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 "TestingFlow.h" + +#include + +#include + +namespace +{ + +void DoTest() +{ + auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); + + FilterType filterType = STREAMLINE; + bool useAsyncComm = false; + + for (vtkm::Id nPerRank = 1; nPerRank < 3; ++nPerRank) + { + for (bool useGhost : { true, false }) + { + for (bool useThreaded : { true, false }) + { + for (bool useBlockIds : { true, false }) + { + //Run blockIds with and without block duplication. + if (useBlockIds && comm.size() > 1) + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, true); + } + else + { + TestPartitionedDataSet( + nPerRank, useGhost, filterType, useThreaded, useAsyncComm, useBlockIds, false); + } + } + } + } + } +} + +} // anonymous namespace + +int UnitTestStreamlineSynchronousMPI(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(DoTest, argc, argv); +} From 47441e841c15a6ea0621f791bd6d430c338173c4 Mon Sep 17 00:00:00 2001 From: roxana bujack Date: Fri, 26 May 2023 14:08:57 +0200 Subject: [PATCH 04/38] add render test for moments --- data/baseline/filter/moments.png | 3 ++ data/baseline/filter/moments0.png | 3 ++ data/baseline/filter/moments12.png | 3 ++ .../image_processing/testing/CMakeLists.txt | 6 ++- .../testing/RenderTestComputeMoments.cxx | 43 +++++++++++++++++++ vtkm/filter/image_processing/vtkm.module | 2 + 6 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 data/baseline/filter/moments.png create mode 100644 data/baseline/filter/moments0.png create mode 100644 data/baseline/filter/moments12.png create mode 100644 vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx diff --git a/data/baseline/filter/moments.png b/data/baseline/filter/moments.png new file mode 100644 index 000000000..63ae037f7 --- /dev/null +++ b/data/baseline/filter/moments.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c077570d0acc5ee81707e1b763e5edbf285af840474d48ab5b051599cb809697 +size 81863 diff --git a/data/baseline/filter/moments0.png b/data/baseline/filter/moments0.png new file mode 100644 index 000000000..2c0f1ff2a --- /dev/null +++ b/data/baseline/filter/moments0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4979a7c0e46943bd7a2c94581023c7db12a30ee12bda735b0041c64cff52196 +size 65438 diff --git a/data/baseline/filter/moments12.png b/data/baseline/filter/moments12.png new file mode 100644 index 000000000..37e3f4c07 --- /dev/null +++ b/data/baseline/filter/moments12.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbd7292ca4006866afc2339e39e14a3edf8c5983e04a5ceea80b5d698293fc86 +size 94505 diff --git a/vtkm/filter/image_processing/testing/CMakeLists.txt b/vtkm/filter/image_processing/testing/CMakeLists.txt index e159e9ddc..5ac223e45 100644 --- a/vtkm/filter/image_processing/testing/CMakeLists.txt +++ b/vtkm/filter/image_processing/testing/CMakeLists.txt @@ -9,13 +9,17 @@ ##============================================================================ set(unit_tests + RenderTestComputeMoments.cxx UnitTestImageDifferenceFilter.cxx UnitTestImageMedianFilter.cxx ) set(libraries vtkm_filter_image_processing - vtkm_source) + vtkm_source + vtkm_rendering + vtkm_rendering_testing +) vtkm_unit_tests( SOURCES ${unit_tests} diff --git a/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx b/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx new file mode 100644 index 000000000..5d6fb2305 --- /dev/null +++ b/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx @@ -0,0 +1,43 @@ +//============================================================================ +// 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 +{ + +void TestComputeMoments() +{ + vtkm::source::Wavelet source; + vtkm::cont::DataSet data = source.Execute(); + + vtkm::filter::image_processing::ComputeMoments filter; + filter.SetActiveField("RTData"); + filter.SetOrder(2); + filter.SetRadius(2); + vtkm::cont::DataSet result = filter.Execute(data); + + vtkm::rendering::testing::RenderTestOptions testOptions; + testOptions.ColorTable = vtkm::cont::ColorTable("inferno"); + testOptions.EnableAnnotations = false; + vtkm::rendering::testing::RenderTest(result, "index", "filter/moments.png", testOptions); + vtkm::rendering::testing::RenderTest(result, "index0", "filter/moments0.png", testOptions); + vtkm::rendering::testing::RenderTest(result, "index12", "filter/moments12.png", testOptions); +} +} // namespace + +int RenderTestComputeMoments(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(TestComputeMoments, argc, argv); +} diff --git a/vtkm/filter/image_processing/vtkm.module b/vtkm/filter/image_processing/vtkm.module index 5fdd1257c..129750e9e 100644 --- a/vtkm/filter/image_processing/vtkm.module +++ b/vtkm/filter/image_processing/vtkm.module @@ -9,3 +9,5 @@ PRIVATE_DEPENDS vtkm_worklet TEST_DEPENDS vtkm_source + vtkm_rendering + vtkm_rendering_testing From ca1fe424cd9a896ff87604519c2c8a9d9ae322d5 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Tue, 30 May 2023 09:49:29 -0600 Subject: [PATCH 05/38] cleanup Camera --- vtkm/rendering/Camera.cxx | 1 - vtkm/rendering/ScalarRenderer.cxx | 13 +++---- vtkm/rendering/raytracing/Camera.cxx | 44 ++++++++++++----------- vtkm/rendering/raytracing/RayOperations.h | 4 +-- vtkm/rendering/testing/RenderTest.h | 2 +- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/vtkm/rendering/Camera.cxx b/vtkm/rendering/Camera.cxx index bbaaaa899..171692d58 100644 --- a/vtkm/rendering/Camera.cxx +++ b/vtkm/rendering/Camera.cxx @@ -153,7 +153,6 @@ void Camera::GetRealViewport(vtkm::Id screenWidth, vtkm::Float32 daspect = (this->Camera2D.Right - this->Camera2D.Left) / (this->Camera2D.Top - this->Camera2D.Bottom); daspect *= this->Camera2D.XScale; -//cerr << "waspect="<(j * w + i); @@ -347,11 +349,13 @@ public: { vtkm::Float32 thx = tanf((fovX * vtkm::Pi_180f()) * .5f); vtkm::Float32 thy = tanf((fovY * vtkm::Pi_180f()) * .5f); + vtkm::Vec3f_32 ru = vtkm::Cross(look, up); vtkm::Normalize(ru); vtkm::Vec3f_32 rv = vtkm::Cross(ru, look); vtkm::Normalize(rv); + delta_x = ru * (2 * thx / (float)w); delta_y = rv * (2 * thy / (float)h); @@ -364,6 +368,7 @@ public: delta_y[1] = delta_y[1] / _zoom; delta_y[2] = delta_y[2] / _zoom; } + nlook = look; vtkm::Normalize(nlook); } @@ -378,14 +383,15 @@ public: Precision& rayDirZ, vtkm::Id& pixelIndex) const { - vtkm::Vec ray_dir(rayDirX, rayDirY, rayDirZ); - int i = vtkm::Int32(idx) % SubsetWidth; - int j = vtkm::Int32(idx) / SubsetWidth; + auto i = vtkm::Int32(idx) % SubsetWidth; + auto j = vtkm::Int32(idx) / SubsetWidth; i += Minx; j += Miny; // Write out the global pixelId pixelIndex = static_cast(j * w + i); - ray_dir = nlook + delta_x * ((2.f * Precision(i) - Precision(w)) / 2.0f) + + + vtkm::Vec ray_dir = nlook + + delta_x * ((2.f * Precision(i) - Precision(w)) / 2.0f) + delta_y * ((2.f * Precision(j) - Precision(h)) / 2.0f); // avoid some numerical issues for (vtkm::Int32 d = 0; d < 3; ++d) @@ -393,12 +399,10 @@ public: if (ray_dir[d] == 0.f) ray_dir[d] += 0.0000001f; } - Precision dot = vtkm::Dot(ray_dir, ray_dir); - Precision sq_mag = vtkm::Sqrt(dot); - - rayDirX = ray_dir[0] / sq_mag; - rayDirY = ray_dir[1] / sq_mag; - rayDirZ = ray_dir[2] / sq_mag; + vtkm::Normalize(ray_dir); + rayDirX = ray_dir[0]; + rayDirY = ray_dir[1]; + rayDirZ = ray_dir[2]; } }; // class perspective ray gen @@ -909,7 +913,7 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, else if (ortho2D) { // 2D rendering has a viewport that represents the area of the canvas where the image - // is drawn. Thus, we have to create rays cooresponding to that region of the + // is drawn. Thus, we have to create rays corresponding to that region of the // canvas, so annotations are correctly rendered vtkm::Float32 vl, vr, vb, vt; this->CameraView.GetRealViewport(this->GetWidth(), this->GetHeight(), vl, vr, vb, vt); diff --git a/vtkm/rendering/raytracing/RayOperations.h b/vtkm/rendering/raytracing/RayOperations.h index 9464ed97e..f94da45c8 100644 --- a/vtkm/rendering/raytracing/RayOperations.h +++ b/vtkm/rendering/raytracing/RayOperations.h @@ -30,8 +30,6 @@ namespace detail class RayStatusFilter : public vtkm::worklet::WorkletMapField { public: - VTKM_CONT - RayStatusFilter() {} using ControlSignature = void(FieldIn, FieldInOut); using ExecutionSignature = void(_1, _2); VTKM_EXEC @@ -205,7 +203,7 @@ public: { vtkm::Vec maskValues; maskValues[0] = RAY_ACTIVE; - vtkm::UInt8 statusUInt8 = static_cast(RAY_ACTIVE); + auto statusUInt8 = static_cast(RAY_ACTIVE); vtkm::cont::ArrayHandle masks; vtkm::worklet::DispatcherMapField> dispatcher{ ( diff --git a/vtkm/rendering/testing/RenderTest.h b/vtkm/rendering/testing/RenderTest.h index 837034562..6aaf43017 100644 --- a/vtkm/rendering/testing/RenderTest.h +++ b/vtkm/rendering/testing/RenderTest.h @@ -98,7 +98,7 @@ struct RenderTestOptions bool LogX = false; bool LogY = false; - std::string Title = ""; + std::string Title; vtkm::Float32 TitleScale = 0.075f; vtkm::Vec2f_32 TitlePosition = { -0.11f, 0.92f }; vtkm::Float32 TitleAngle = 0; From b4f17b85186796c64f6eb70a449bb0a359ef219b Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Tue, 30 May 2023 10:02:33 -0600 Subject: [PATCH 06/38] use unique_ptr for PIMPL for View --- vtkm/rendering/View.cxx | 6 +++--- vtkm/rendering/View.h | 4 ++-- vtkm/rendering/View1D.cxx | 4 +--- vtkm/rendering/View1D.h | 2 -- vtkm/rendering/View2D.cxx | 2 -- vtkm/rendering/View2D.h | 2 -- vtkm/rendering/View3D.cxx | 2 -- vtkm/rendering/View3D.h | 2 -- 8 files changed, 6 insertions(+), 18 deletions(-) diff --git a/vtkm/rendering/View.cxx b/vtkm/rendering/View.cxx index f99e5f87e..dfff42ca0 100644 --- a/vtkm/rendering/View.cxx +++ b/vtkm/rendering/View.cxx @@ -37,7 +37,7 @@ View::View(const vtkm::rendering::Scene& scene, const vtkm::rendering::Canvas& canvas, const vtkm::rendering::Color& backgroundColor, const vtkm::rendering::Color& foregroundColor) - : Internal(std::make_shared()) + : Internal(std::make_unique()) { this->Internal->Scene = scene; this->Internal->MapperPointer = mapper.NewCopy(); @@ -65,7 +65,7 @@ View::View(const vtkm::rendering::Scene& scene, const vtkm::rendering::Camera& camera, const vtkm::rendering::Color& backgroundColor, const vtkm::rendering::Color& foregroundColor) - : Internal(std::make_shared()) + : Internal(std::make_unique()) { this->Internal->Scene = scene; this->Internal->MapperPointer = mapper.NewCopy(); @@ -77,7 +77,7 @@ View::View(const vtkm::rendering::Scene& scene, this->AxisColor = foregroundColor; } -View::~View() {} +View::~View() = default; const vtkm::rendering::Scene& View::GetScene() const { diff --git a/vtkm/rendering/View.h b/vtkm/rendering/View.h index e964c136d..e2361b432 100644 --- a/vtkm/rendering/View.h +++ b/vtkm/rendering/View.h @@ -90,7 +90,7 @@ public: void SetWorldAnnotationsEnabled(bool val) { this->WorldAnnotationsEnabled = val; } VTKM_CONT void SetRenderAnnotationsEnabled(bool val) { this->RenderAnnotationsEnabled = val; } - VTKM_CONT bool GetRenderAnnotationsEnabled() { return this->RenderAnnotationsEnabled; } + VTKM_CONT bool GetRenderAnnotationsEnabled() const { return this->RenderAnnotationsEnabled; } virtual void Paint() = 0; virtual void RenderScreenAnnotations() = 0; @@ -126,7 +126,7 @@ protected: bool RenderAnnotationsEnabled = true; private: - std::shared_ptr Internal; + std::unique_ptr Internal; }; } // namespace vtkm::rendering diff --git a/vtkm/rendering/View1D.cxx b/vtkm/rendering/View1D.cxx index d6c6fcb58..80cff6990 100644 --- a/vtkm/rendering/View1D.cxx +++ b/vtkm/rendering/View1D.cxx @@ -36,8 +36,6 @@ View1D::View1D(const vtkm::rendering::Scene& scene, { } -View1D::~View1D() {} - void View1D::Paint() { this->GetCanvas().Clear(); @@ -104,7 +102,7 @@ void View1D::RenderColorLegendAnnotations() this->GetCanvas().BeginTextRenderingBatch(); for (int i = 0; i < this->GetScene().GetNumberOfActors(); ++i) { - vtkm::rendering::Actor act = this->GetScene().GetActor(i); + const auto& act = this->GetScene().GetActor(i); vtkm::Vec colorData; act.GetColorTable().GetPoint(0, colorData); diff --git a/vtkm/rendering/View1D.h b/vtkm/rendering/View1D.h index 2af6b3fa1..6366d0cc7 100644 --- a/vtkm/rendering/View1D.h +++ b/vtkm/rendering/View1D.h @@ -35,8 +35,6 @@ public: const vtkm::rendering::Color& backgroundColor = vtkm::rendering::Color(0, 0, 0, 1), const vtkm::rendering::Color& foregroundColor = vtkm::rendering::Color(1, 1, 1, 1)); - ~View1D(); - void Paint() override; void RenderScreenAnnotations() override; void RenderWorldAnnotations() override; diff --git a/vtkm/rendering/View2D.cxx b/vtkm/rendering/View2D.cxx index 47b97d96a..d639a9660 100644 --- a/vtkm/rendering/View2D.cxx +++ b/vtkm/rendering/View2D.cxx @@ -34,8 +34,6 @@ View2D::View2D(const vtkm::rendering::Scene& scene, { } -View2D::~View2D() {} - void View2D::Paint() { this->GetCanvas().Clear(); diff --git a/vtkm/rendering/View2D.h b/vtkm/rendering/View2D.h index f292e6ec9..5e358931f 100644 --- a/vtkm/rendering/View2D.h +++ b/vtkm/rendering/View2D.h @@ -36,8 +36,6 @@ public: const vtkm::rendering::Color& backgroundColor = vtkm::rendering::Color(0, 0, 0, 1), const vtkm::rendering::Color& foregroundColor = vtkm::rendering::Color(1, 1, 1, 1)); - ~View2D(); - void Paint() override; void RenderScreenAnnotations() override; diff --git a/vtkm/rendering/View3D.cxx b/vtkm/rendering/View3D.cxx index aa5076120..78322f6b1 100644 --- a/vtkm/rendering/View3D.cxx +++ b/vtkm/rendering/View3D.cxx @@ -34,8 +34,6 @@ View3D::View3D(const vtkm::rendering::Scene& scene, { } -View3D::~View3D() {} - void View3D::Paint() { this->GetCanvas().Clear(); diff --git a/vtkm/rendering/View3D.h b/vtkm/rendering/View3D.h index 2648f1676..4246b670d 100644 --- a/vtkm/rendering/View3D.h +++ b/vtkm/rendering/View3D.h @@ -37,8 +37,6 @@ public: const vtkm::rendering::Color& backgroundColor = vtkm::rendering::Color(0, 0, 0, 1), const vtkm::rendering::Color& foregroundColor = vtkm::rendering::Color(1, 1, 1, 1)); - ~View3D(); - void Paint() override; void RenderScreenAnnotations() override; From 6d69301b785b7e7f1493bba0cb42ad5248a0bcc3 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Fri, 3 Mar 2023 16:37:54 -0500 Subject: [PATCH 07/38] DIY: bump new version --- vtkm/thirdparty/diy/update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtkm/thirdparty/diy/update.sh b/vtkm/thirdparty/diy/update.sh index 3af40e5cd..5d7706f72 100755 --- a/vtkm/thirdparty/diy/update.sh +++ b/vtkm/thirdparty/diy/update.sh @@ -8,7 +8,7 @@ readonly name="diy" readonly ownership="Diy Upstream " readonly subtree="vtkm/thirdparty/$name/vtkm$name" readonly repo="https://gitlab.kitware.com/third-party/diy2.git" -readonly tag="for/vtk-m-20220914-master-g0f1c387" +readonly tag="for/vtk-m-20230328-g9bea15a1" readonly paths=" cmake include From 928900c63df9a1dc8d84089cf51f62558c6e3581 Mon Sep 17 00:00:00 2001 From: Diy Upstream Date: Tue, 28 Mar 2023 16:35:18 -0400 Subject: [PATCH 08/38] diy 2023-03-28 (6837fb55) Code extracted from: https://gitlab.kitware.com/third-party/diy2.git at commit 6837fb55f24a9a38dfb2b6a481cc4de5f7ac455d (for/vtk-m-20230328-g9bea15a1). --- CMakeLists.txt | 42 +- cmake/diy-config.cmake.in | 6 +- include/vtkmdiy/collection.hpp | 8 +- .../vtkmdiy/detail/master/communication.hpp | 31 +- include/vtkmdiy/detail/master/execution.hpp | 2 + include/vtkmdiy/dynamic-point.hpp | 6 +- include/vtkmdiy/io/shared.hpp | 4 +- include/vtkmdiy/io/utils.hpp | 2 + include/vtkmdiy/log.hpp | 4 +- include/vtkmdiy/master.hpp | 131 ++- include/vtkmdiy/mpi/config.hpp | 17 +- include/vtkmdiy/mpi/mpi_cast.hpp | 7 +- include/vtkmdiy/mpi/mpitypes.hpp.in | 31 +- include/vtkmdiy/mpi/no-mpi.hpp | 35 +- include/vtkmdiy/mpi/optional.hpp | 2 +- include/vtkmdiy/mpi/window.cpp | 30 +- include/vtkmdiy/mpi/window.hpp | 45 +- include/vtkmdiy/proxy.hpp | 24 + include/vtkmdiy/reduce.hpp | 2 +- include/vtkmdiy/serialization.hpp | 106 ++- include/vtkmdiy/storage.hpp | 14 +- .../{chobo => itlib}/small_vector.hpp | 859 ++++-------------- include/vtkmdiy/thread.hpp | 3 + include/vtkmdiy/version.hpp | 2 +- 24 files changed, 607 insertions(+), 806 deletions(-) rename include/vtkmdiy/thirdparty/{chobo => itlib}/small_vector.hpp (50%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46861ebdc..c02928b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,13 @@ macro (diy_dependent_option variable) endif () endmacro () +set (compiler_supports_sanitizers OFF) +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR + CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR + CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set (compiler_supports_sanitizers ON) +endif () + diy_option (threads "Build DIY with threading" ON) diy_option (log "Build DIY with logging" OFF) diy_option (profile "Build DIY with profiling" OFF) @@ -44,6 +51,8 @@ diy_dependent_option (BUILD_SHARED_LIBS "Create shared libraries if on" diy_dependent_option (build_diy_nompi_lib "Also build the nompi version of diy::mpi" OFF "mpi;build_diy_mpi_lib" OFF) diy_option (build_examples "Build DIY examples" ON) diy_option (build_tests "Build DIY tests" ON) +diy_option (python "Build Python bindings" OFF) +cmake_dependent_option (enable_sanitizers "Build DIY with sanitizer support" OFF "compiler_supports_sanitizers" OFF) # Default to Release if (NOT CMAKE_BUILD_TYPE) @@ -64,9 +73,8 @@ endif () # Logging if (log) - list (APPEND diy_definitions "-DVTKMDIY_USE_SPDLOG") - find_path (SPDLOG_INCLUDE_DIR spdlog/spdlog.h) - list (APPEND diy_include_thirdparty_directories $) + list (APPEND diy_definitions "-DVTMDIY_USE_SPDLOG") + find_package (spdlog REQUIRED) endif() # Profiling @@ -114,8 +122,12 @@ if (NOT DEFINED diy_export_name) set(diy_export_name "diy_targets") endif() -set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") -set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +if (NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +endif() +if (NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +endif() # for diy_developer_flags include(DIYCompilerFlags) @@ -152,6 +164,9 @@ function(add_diy_mpi_library use_mpi) target_include_directories(${lib_name} SYSTEM PRIVATE ${diy_include_directories}) # for mpitypes.hpp target_include_directories(${lib_name} SYSTEM PRIVATE ${diy_include_thirdparty_directories}) target_link_libraries(${lib_name} PRIVATE diy_developer_flags) + if (log) + target_link_libraries(${lib_name} PUBLIC spdlog::spdlog_header_only) + endif () if (use_mpi AND TARGET MPI::MPI_CXX) target_link_libraries(${lib_name} PRIVATE MPI::MPI_CXX) endif() @@ -195,6 +210,9 @@ target_include_directories(${diy_prefix} SYSTEM INTERFACE ${diy_include_thirdpar if (diy_include_directories) target_include_directories(${diy_prefix} SYSTEM INTERFACE ${diy_include_directories}) endif() +if (log) + target_link_libraries(${diy_prefix} INTERFACE spdlog::spdlog_header_only) +endif () target_link_libraries(${diy_prefix} INTERFACE ${diy_libraries}) if (NOT build_diy_mpi_lib) if (mpi) @@ -224,6 +242,16 @@ elseif (${diy_prefix}mpi_nompi IN_LIST diy_targets) endif() list(APPEND libraries diy_developer_flags) +# Sanitizers +if (enable_sanitizers) + set(sanitizer "address" CACHE STRING "The sanitizer to use") + + string (APPEND CMAKE_CXX_FLAGS " -fsanitize=${sanitizer}") + string (APPEND CMAKE_C_FLAGS " -fsanitize=${sanitizer}") + string (APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=${sanitizer}") + string (APPEND CMAKE_SHARED_LINKER_FLAGS " -fsanitize=${sanitizer}") +endif () + # enable testing and CDash dashboard submission enable_testing () include (CTest) @@ -262,3 +290,7 @@ if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) # Only generate these files wh install(EXPORT ${diy_export_name} NAMESPACE DIY:: DESTINATION "." FILE diy-targets.cmake) install(FILES "${PROJECT_BINARY_DIR}/diy-config.cmake" DESTINATION ".") endif() + +if (python) + add_subdirectory(bindings/python) +endif (python) diff --git a/cmake/diy-config.cmake.in b/cmake/diy-config.cmake.in index 9feb91b65..6f0b07168 100644 --- a/cmake/diy-config.cmake.in +++ b/cmake/diy-config.cmake.in @@ -25,12 +25,10 @@ if (threads) endif() if (log) - find_path(SPDLOG_INCLUDE_DIR "spdlog/spdlog.h") - if (SPDLOG_INCLUDE_DIR STREQUAL "SPDLOG_INCLUDE_DIR-NOTFOUND") + find_package(spdlog ${_diy_find_quietly}) + if (NOT spdlog_FOUND) list(APPEND "${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE" "SPDLOG not found") set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 0) - else() - target_include_directories(DIY::@diy_prefix@ INTERFACE $) endif() endif() diff --git a/include/vtkmdiy/collection.hpp b/include/vtkmdiy/collection.hpp index 206b94b76..e03f061c5 100644 --- a/include/vtkmdiy/collection.hpp +++ b/include/vtkmdiy/collection.hpp @@ -17,10 +17,10 @@ namespace diy typedef std::vector Elements; typedef critical_resource CInt; - typedef void* (*Create)(); - typedef void (*Destroy)(void*); - typedef detail::Save Save; - typedef detail::Load Load; + using Create = std::function; + using Destroy = std::function; + using Save = detail::Save; + using Load = detail::Load; public: Collection(Create create__, diff --git a/include/vtkmdiy/detail/master/communication.hpp b/include/vtkmdiy/detail/master/communication.hpp index c9133ed6f..1f6b0800f 100644 --- a/include/vtkmdiy/detail/master/communication.hpp +++ b/include/vtkmdiy/detail/master/communication.hpp @@ -5,11 +5,13 @@ namespace diy int from, to; int nparts; int round; + int nblobs; }; struct Master::InFlightSend { std::shared_ptr message; + BinaryBlob blob; mpi::request request; MessageInfo info; // for debug purposes @@ -18,12 +20,18 @@ namespace diy struct Master::InFlightRecv { MemoryBuffer message; - MessageInfo info { -1, -1, -1, -1 }; + MessageInfo info { -1, -1, -1, -1, -1 }; bool done = false; + MemoryManagement mem; inline bool recv(mpi::communicator& comm, const mpi::status& status); inline void place(IncomingRound* in, bool unload, ExternalStorage* storage, IExchangeInfo* iexchange); - void reset() { *this = InFlightRecv(); } + void reset() + { + MemoryManagement mem_ = mem; + *this = InFlightRecv(); + mem = mem_; + } }; struct Master::InFlightRecvsMap: public std::map @@ -111,7 +119,7 @@ recv(mpi::communicator& comm, const mpi::status& status) result = true; } - else + else if (info.nparts > 0) { size_t start_idx = message.buffer.size(); size_t count = status.count(); @@ -124,9 +132,24 @@ recv(mpi::communicator& comm, const mpi::status& status) comm.recv(status.source(), status.tag(), window); info.nparts--; + } else if (info.nblobs > 0) + { + size_t count = status.count(); + detail::VectorWindow window; + + char* buffer = mem.allocate(info.to, count); + + window.begin = buffer; + window.count = count; + + comm.recv(status.source(), status.tag(), window); + + message.save_binary_blob(buffer, count, mem.deallocate); + + info.nblobs--; } - if (info.nparts == 0) + if (info.nparts == 0 && info.nblobs == 0) done = true; return result; diff --git a/include/vtkmdiy/detail/master/execution.hpp b/include/vtkmdiy/detail/master/execution.hpp index 4a382a562..85750e9aa 100644 --- a/include/vtkmdiy/detail/master/execution.hpp +++ b/include/vtkmdiy/detail/master/execution.hpp @@ -1,3 +1,5 @@ +#include + struct diy::Master::ProcessBlock { ProcessBlock(Master& master_, diff --git a/include/vtkmdiy/dynamic-point.hpp b/include/vtkmdiy/dynamic-point.hpp index 21a9f6367..4c24551ad 100644 --- a/include/vtkmdiy/dynamic-point.hpp +++ b/include/vtkmdiy/dynamic-point.hpp @@ -7,17 +7,17 @@ #include #include "constants.h" -#include "thirdparty/chobo/small_vector.hpp" +#include "thirdparty/itlib/small_vector.hpp" namespace diy { template -class DynamicPoint: public chobo::small_vector +class DynamicPoint: public itlib::small_vector { public: using Coordinate = Coordinate_; - using Parent = chobo::small_vector; + using Parent = itlib::small_vector; template struct rebind { typedef DynamicPoint type; }; diff --git a/include/vtkmdiy/io/shared.hpp b/include/vtkmdiy/io/shared.hpp index c143b241f..4c2e34444 100644 --- a/include/vtkmdiy/io/shared.hpp +++ b/include/vtkmdiy/io/shared.hpp @@ -30,9 +30,9 @@ class SharedOutFile: public std::ostringstream diy::mpi::gather(world_, contents, all_contents, root_); // write the file serially - std::ofstream out(filename_); + std::ofstream fout(filename_); for (auto& cntnts : all_contents) - out.write(cntnts.data(), cntnts.size()); + fout.write(cntnts.data(), cntnts.size()); } else diy::mpi::gather(world_, contents, root_); } diff --git a/include/vtkmdiy/io/utils.hpp b/include/vtkmdiy/io/utils.hpp index b096289c6..1474e6057 100644 --- a/include/vtkmdiy/io/utils.hpp +++ b/include/vtkmdiy/io/utils.hpp @@ -5,6 +5,8 @@ #include #include #include +#define NOMINMAX +#include #else #include // mkstemp() on Mac #include diff --git a/include/vtkmdiy/log.hpp b/include/vtkmdiy/log.hpp index 292851ccc..57e017c31 100644 --- a/include/vtkmdiy/log.hpp +++ b/include/vtkmdiy/log.hpp @@ -55,8 +55,8 @@ set_logger(Args...) #include #include -#include -#include +#include +#include namespace diy { diff --git a/include/vtkmdiy/master.hpp b/include/vtkmdiy/master.hpp index ccca263f9..bf53df591 100644 --- a/include/vtkmdiy/master.hpp +++ b/include/vtkmdiy/master.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "link.hpp" #include "collection.hpp" @@ -28,6 +29,23 @@ namespace diy { + + struct MemoryManagement + { + using Allocate = std::function; + using Deallocate = BinaryBlob::Deleter; + using MemCopy = std::function; + + MemoryManagement() = default; + MemoryManagement(Allocate allocate_, Deallocate deallocate_, MemCopy copy_): + allocate(allocate_), deallocate(deallocate_), copy(copy_) {} + + Allocate allocate = [](int /* gid */, size_t n) { return new char[n]; }; + Deallocate deallocate = [](const char* p) { delete[] p; }; + MemCopy copy = [](char* dest, const char* src, size_t count) { std::memcpy(dest, src, count); }; + }; + + // Stores and manages blocks; initiates serialization and communication when necessary. // // Provides a foreach function, which is meant as the main entry point. @@ -126,6 +144,8 @@ namespace diy void unload(ExternalStorage* storage) { size_ = buffer_.size(); external_ = storage->put(buffer_); } void load(ExternalStorage* storage) { storage->get(external_, buffer_); external_ = -1; } + MemoryBuffer& buffer() { return buffer_; } + private: size_t size_; int external_; @@ -147,7 +167,6 @@ namespace diy }; typedef std::map IncomingRoundMap; - public: /** * \ingroup Initialization @@ -173,6 +192,7 @@ namespace diy inline void destroy(int i) { if (blocks_.own()) blocks_.destroy(i); } inline int add(int gid, void* b, Link* l); //!< add a block + inline int add(int gid, void* b, const Link& l){ return add(gid, b, l.clone()); } inline void* release(int i); //!< release ownership of the block //!< return the `i`-th block @@ -213,17 +233,17 @@ namespace diy bool local(int gid__) const { return lids_.find(gid__) != lids_.end(); } //! exchange the queues between all the blocks (collective operation) - inline void exchange(bool remote = false); + inline void exchange(bool remote = false, MemoryManagement mem = MemoryManagement()); //! nonblocking exchange of the queues between all the blocks template - void iexchange_(const ICallback& f); + void iexchange_(const ICallback& f, MemoryManagement mem); template - void iexchange(const F& f) + void iexchange(const F& f, MemoryManagement mem = MemoryManagement()) { using Block = typename detail::block_traits::type; - iexchange_(f); + iexchange_(f, mem); } inline void process_collectives(); @@ -283,29 +303,30 @@ namespace diy public: // Communicator functionality - inline void flush(bool remote = false); // makes sure all the serialized queues migrate to their target processors + inline void flush(bool remote, MemoryManagement mem = MemoryManagement()); // makes sure all the serialized queues migrate to their target processors private: // Communicator functionality - inline void comm_exchange(GidSendOrder& gid_order, IExchangeInfo* iex = 0); - inline void rcomm_exchange(); // possibly called in between block computations + inline void comm_exchange(GidSendOrder& gid_order, MemoryManagement mem, IExchangeInfo* iex = 0); + inline void rcomm_exchange(MemoryManagement mem); // possibly called in between block computations inline bool nudge(IExchangeInfo* iex = 0); - inline void send_queue(int from_gid, int to_gid, int to_proc, QueueRecord& qr, bool remote, IExchangeInfo* iex); + inline void send_queue(int from_gid, int to_gid, int to_proc, QueueRecord& qr, bool remote, MemoryManagement mem, IExchangeInfo* iex); inline void send_outgoing_queues(GidSendOrder& gid_order, bool remote, + MemoryManagement mem, IExchangeInfo* iex = 0); - inline void check_incoming_queues(IExchangeInfo* iex = 0); + inline void check_incoming_queues(MemoryManagement mem, IExchangeInfo* iex = 0); inline GidSendOrder order_gids(); inline void touch_queues(); - inline void send_same_rank(int from, int to, QueueRecord& qr, IExchangeInfo* iex); + inline void send_same_rank(int from, int to, QueueRecord& qr, MemoryManagement mem, IExchangeInfo* iex); inline void send_different_rank(int from, int to, int proc, QueueRecord& qr, bool remote, IExchangeInfo* iex); inline InFlightRecv& inflight_recv(int proc); inline InFlightSendsList& inflight_sends(); // iexchange commmunication - inline void icommunicate(IExchangeInfo* iex); // async communication + inline void icommunicate(IExchangeInfo* iex, MemoryManagement mem); // async communication struct tags { enum { queue, @@ -607,7 +628,7 @@ foreach_(const Callback& f, const Skip& skip) void diy::Master:: -exchange(bool remote) +exchange(bool remote, MemoryManagement mem) { auto scoped = prof.scoped("exchange"); VTKMDIY_UNUSED(scoped); @@ -625,7 +646,7 @@ exchange(bool remote) if (!remote) touch_queues(); - flush(remote); + flush(remote, mem); log->debug("Finished exchange"); } @@ -658,7 +679,7 @@ touch_queues() template void diy::Master:: -iexchange_(const ICallback& f) +iexchange_(const ICallback& f, MemoryManagement mem) { auto scoped = prof.scoped("iexchange"); VTKMDIY_UNUSED(scoped); @@ -685,11 +706,11 @@ iexchange_(const ICallback& f) thread comm_thread; if (threads() > 1) - comm_thread = thread([this,&iex]() + comm_thread = thread([this,&iex,mem]() { while(!iex.all_done()) { - icommunicate(&iex); + icommunicate(&iex, mem); iex.control(); //std::this_thread::sleep_for(std::chrono::microseconds(1)); } @@ -713,7 +734,7 @@ iexchange_(const ICallback& f) stats::Annotation::Guard g( stats::Annotation("diy.block").set(gid) ); if (threads() == 1) - icommunicate(&iex); + icommunicate(&iex, mem); bool done = done_result[gid]; if (!done || !empty_incoming(gid)) { @@ -762,17 +783,17 @@ iexchange_(const ICallback& f) /* Communicator */ void diy::Master:: -comm_exchange(GidSendOrder& gid_order, IExchangeInfo* iex) +comm_exchange(GidSendOrder& gid_order, MemoryManagement mem, IExchangeInfo* iex) { auto scoped = prof.scoped("comm-exchange"); VTKMDIY_UNUSED(scoped); - send_outgoing_queues(gid_order, false, iex); + send_outgoing_queues(gid_order, false, mem, iex); while(nudge(iex)) // kick requests ; - check_incoming_queues(iex); + check_incoming_queues(mem, iex); } /* Remote communicator */ @@ -803,7 +824,7 @@ comm_exchange(GidSendOrder& gid_order, IExchangeInfo* iex) // void diy::Master:: -rcomm_exchange() +rcomm_exchange(MemoryManagement mem) { bool done = false; bool ibarr_act = false; @@ -814,12 +835,12 @@ rcomm_exchange() while (!done) { - send_outgoing_queues(gid_order, true, 0); + send_outgoing_queues(gid_order, true, mem, 0); // kick requests nudge(); - check_incoming_queues(); + check_incoming_queues(mem); if (ibarr_act) { if (ibarr_req.test()) @@ -877,7 +898,7 @@ order_gids() // iexchange communicator void diy::Master:: -icommunicate(IExchangeInfo* iex) +icommunicate(IExchangeInfo* iex, MemoryManagement mem) { auto scoped = prof.scoped("icommunicate"); VTKMDIY_UNUSED(scoped); @@ -887,7 +908,7 @@ icommunicate(IExchangeInfo* iex) auto gid_order = order_gids(); // exchange - comm_exchange(gid_order, iex); + comm_exchange(gid_order, mem, iex); // cleanup @@ -906,6 +927,7 @@ send_queue(int from_gid, int to_proc, QueueRecord& qr, bool remote, + MemoryManagement mem, IExchangeInfo* iex) { stats::Annotation::Guard gb( stats::Annotation("diy.block").set(from_gid) ); @@ -917,7 +939,7 @@ send_queue(int from_gid, log->debug("[{}] Sending queue: {} <- {} of size {}, iexchange = {}", comm_.rank(), to_gid, from_gid, qr.size(), iex ? 1 : 0); if (to_proc == comm_.rank()) // sending to same rank, simply swap buffers - send_same_rank(from_gid, to_gid, qr, iex); + send_same_rank(from_gid, to_gid, qr, mem, iex); else // sending to an actual message to a different rank send_different_rank(from_gid, to_gid, to_proc, qr, remote, iex); } @@ -926,6 +948,7 @@ void diy::Master:: send_outgoing_queues(GidSendOrder& gid_order, bool remote, // TODO: are remote and iexchange mutually exclusive? If so, use single enum? + MemoryManagement mem, IExchangeInfo* iex) { auto scoped = prof.scoped("send-outgoing-queues"); @@ -950,7 +973,7 @@ send_outgoing_queues(GidSendOrder& gid_order, access.unlock(); // others can push on this queue, while we are working assert(!qr.external()); log->debug("Processing queue: {} <- {} of size {}", to_gid, from, qr.size()); - send_queue(from, to_gid, to_proc, qr, remote, iex); + send_queue(from, to_gid, to_proc, qr, remote, mem, iex); access.lock(); } } @@ -978,7 +1001,7 @@ send_outgoing_queues(GidSendOrder& gid_order, // NB: send only front auto& qr = access->front(); log->debug("Processing queue: {} <- {} of size {}", to_gid, from_gid, qr.size()); - send_queue(from_gid, to_gid, to_proc, qr, remote, iex); + send_queue(from_gid, to_gid, to_proc, qr, remote, mem, iex); access->pop_front(); } } @@ -987,7 +1010,7 @@ send_outgoing_queues(GidSendOrder& gid_order, void diy::Master:: -send_same_rank(int from, int to, QueueRecord& qr, IExchangeInfo*) +send_same_rank(int from, int to, QueueRecord& qr, MemoryManagement mem, IExchangeInfo*) { auto scoped = prof.scoped("send-same-rank"); @@ -997,9 +1020,24 @@ send_same_rank(int from, int to, QueueRecord& qr, IExchangeInfo*) auto access_incoming = current_incoming.map[to][from].access(); + // save blobs to copy them explicitly + std::vector blobs; + qr.buffer().blobs.swap(blobs); + qr.buffer().blob_position = 0; + access_incoming->emplace_back(std::move(qr)); QueueRecord& in_qr = access_incoming->back(); + // copy blobs explicitly; we cannot just move them in place, since we don't + // own their memory and must guarantee that it's safe to free, once + // exchange() is done + for (BinaryBlob& blob : blobs) + { + char* p = mem.allocate(to, blob.size); + mem.copy(p, blob.pointer.get(), blob.size); + in_qr.buffer().save_binary_blob(p, blob.size, mem.deallocate); + } + if (!in_qr.external()) { in_qr.reset(); @@ -1029,7 +1067,7 @@ send_different_rank(int from, int to, int proc, QueueRecord& qr, bool remote, IE // sending to a different rank std::shared_ptr buffer = std::make_shared(qr.move()); - MessageInfo info{from, to, 1, exchange_round_}; + MessageInfo info{from, to, 1, exchange_round_, static_cast(buffer->nblobs())}; // size fits in one message if (Serialization::size(*buffer) + Serialization::size(info) <= MAX_MPI_MESSAGE_COUNT) { @@ -1103,11 +1141,33 @@ send_different_rank(int from, int to, int proc, QueueRecord& qr, bool remote, IE inflight_send.message = buffer; } } // large message broken into pieces + + // send binary blobs + for (size_t i = 0; i < buffer->nblobs(); ++i) + { + auto blob = buffer->load_binary_blob(); + assert(blob.size < MAX_MPI_MESSAGE_COUNT); // for now assume blobs are small enough that we don't need to break them into multiple parts + + inflight_sends().emplace_back(); + auto& inflight_send = inflight_sends().back(); + + inflight_send.info = info; + + detail::VectorWindow window; + window.begin = const_cast(blob.pointer.get()); + window.count = blob.size; + + if (remote || iex) + inflight_send.request = comm_.issend(proc, tags::queue, window); + else + inflight_send.request = comm_.isend(proc, tags::queue, window); + inflight_send.blob = std::move(blob); + } } void diy::Master:: -check_incoming_queues(IExchangeInfo* iex) +check_incoming_queues(MemoryManagement mem, IExchangeInfo* iex) { auto scoped = prof.scoped("check-incoming-queues"); VTKMDIY_UNUSED(scoped); @@ -1116,6 +1176,7 @@ check_incoming_queues(IExchangeInfo* iex) while (ostatus) { InFlightRecv& ir = inflight_recv(ostatus->source()); + ir.mem = mem; if (iex) iex->inc_work(); // increment work before sender's issend request can complete (so we are now responsible for the queue) @@ -1141,7 +1202,7 @@ check_incoming_queues(IExchangeInfo* iex) void diy::Master:: -flush(bool remote) +flush(bool remote, MemoryManagement mem) { #ifdef VTKMDIY_DEBUG time_type start = get_time(); @@ -1155,13 +1216,13 @@ flush(bool remote) if (remote) - rcomm_exchange(); + rcomm_exchange(mem); else { auto gid_order = order_gids(); do { - comm_exchange(gid_order); + comm_exchange(gid_order, mem); #ifdef VTKMDIY_DEBUG time_type cur = get_time(); diff --git a/include/vtkmdiy/mpi/config.hpp b/include/vtkmdiy/mpi/config.hpp index b8a6643af..13fa54c81 100644 --- a/include/vtkmdiy/mpi/config.hpp +++ b/include/vtkmdiy/mpi/config.hpp @@ -1,6 +1,8 @@ #ifndef VTKMDIY_MPI_CONFIG_HPP #define VTKMDIY_MPI_CONFIG_HPP +#include + /// We want to allow the use of `diy::mpi` in either header-only or library mode. /// VTKMDIY_MPI_AS_LIB is defined when using library mode. /// This file contains some configuration macros. To maintain backwards compatibility @@ -49,13 +51,26 @@ struct DIY_##mpitype { \ mpitype data; \ }; +#define DEFINE_DIY_MPI_TYPE_MOVE(mpitype) \ +struct DIY_##mpitype { \ + DIY_##mpitype() = default; \ + DIY_##mpitype(const mpitype&) = delete; \ + DIY_##mpitype(mpitype&& obj) : data(std::move(obj)) {} \ + DIY_##mpitype& operator=(const mpitype&) = delete; \ + DIY_##mpitype& operator=(mpitype&& obj) { data = std::move(obj); return *this; } \ + operator const mpitype&() const { return data; } \ + void reset() { data = mpitype(); } \ +private: \ + mpitype data; \ +}; + DEFINE_DIY_MPI_TYPE(MPI_Comm) DEFINE_DIY_MPI_TYPE(MPI_Datatype) DEFINE_DIY_MPI_TYPE(MPI_Status) DEFINE_DIY_MPI_TYPE(MPI_Request) DEFINE_DIY_MPI_TYPE(MPI_Op) DEFINE_DIY_MPI_TYPE(MPI_File) -DEFINE_DIY_MPI_TYPE(MPI_Win) +DEFINE_DIY_MPI_TYPE_MOVE(MPI_Win) #undef DEFINE_DIY_MPI_TYPE diff --git a/include/vtkmdiy/mpi/mpi_cast.hpp b/include/vtkmdiy/mpi/mpi_cast.hpp index 960742ae1..6802a2d23 100644 --- a/include/vtkmdiy/mpi/mpi_cast.hpp +++ b/include/vtkmdiy/mpi/mpi_cast.hpp @@ -18,13 +18,18 @@ inline mpitype& mpi_cast(DIY_##mpitype& obj) { return *reinterpret_cast(&obj); } \ inline DIY_##mpitype make_DIY_##mpitype(const mpitype& obj) { DIY_##mpitype ret; mpi_cast(ret) = obj; return ret; } +#define DEFINE_MPI_CAST_MOVE(mpitype) \ +inline mpitype& mpi_cast(DIY_##mpitype& obj) { return *reinterpret_cast(&obj); } \ +inline const mpitype& mpi_cast(const DIY_##mpitype& obj) { return *reinterpret_cast(&obj); } \ +inline DIY_##mpitype make_DIY_##mpitype(mpitype&& obj) { DIY_##mpitype ret = std::move(obj); return ret; } + DEFINE_MPI_CAST(MPI_Comm) DEFINE_MPI_CAST(MPI_Datatype) DEFINE_MPI_CAST(MPI_Status) DEFINE_MPI_CAST(MPI_Request) DEFINE_MPI_CAST(MPI_Op) DEFINE_MPI_CAST(MPI_File) -DEFINE_MPI_CAST(MPI_Win) +DEFINE_MPI_CAST_MOVE(MPI_Win) #undef DEFINE_MPI_CAST diff --git a/include/vtkmdiy/mpi/mpitypes.hpp.in b/include/vtkmdiy/mpi/mpitypes.hpp.in index bea375fd8..aa467b448 100644 --- a/include/vtkmdiy/mpi/mpitypes.hpp.in +++ b/include/vtkmdiy/mpi/mpitypes.hpp.in @@ -1,6 +1,8 @@ #ifndef VTKMDIY_MPI_MPITYPES_H #define VTKMDIY_MPI_MPITYPES_H +#include + #cmakedefine TYPESIZE_MPI_Comm @TYPESIZE_MPI_Comm@ #cmakedefine TYPESIZE_MPI_Datatype @TYPESIZE_MPI_Datatype@ #cmakedefine TYPESIZE_MPI_Status @TYPESIZE_MPI_Status@ @@ -18,6 +20,7 @@ namespace mpi # define ASSERT_MPI_TYPE_SIZE(mpitype) static_assert(sizeof(mpitype) <= sizeof(DIY_##mpitype), ""); #else # define ASSERT_MPI_TYPE_SIZE(mpitype) +struct MPI_Win; #endif #define DEFINE_DIY_MPI_TYPE(mpitype) \ @@ -26,15 +29,41 @@ struct DIY_##mpitype { \ }; \ ASSERT_MPI_TYPE_SIZE(mpitype) +#define DEFINE_DIY_MPI_TYPE_MOVE(mpitype) \ + struct DIY_##mpitype \ + { \ + DIY_##mpitype() = default; \ + DIY_##mpitype(const mpitype&) = delete; \ + DIY_##mpitype& operator=(const mpitype&) = delete; \ + DIY_##mpitype(mpitype&& obj) \ + { \ + std::memcpy(data, &obj, TYPESIZE_##mpitype); \ + std::memset(&obj, 0, TYPESIZE_##mpitype); \ + } \ + DIY_##mpitype& operator=(mpitype&& obj) \ + { \ + std::memcpy(data, &obj, TYPESIZE_##mpitype); \ + std::memset(&obj, 0, TYPESIZE_##mpitype); \ + return *this; \ + } \ + operator const mpitype&() const { return *reinterpret_cast(data); } \ + void reset() { std::memset(data, 0, TYPESIZE_##mpitype); } \ + \ + private: \ + char* data[TYPESIZE_##mpitype]; \ + }; \ + ASSERT_MPI_TYPE_SIZE(mpitype); + DEFINE_DIY_MPI_TYPE(MPI_Comm) DEFINE_DIY_MPI_TYPE(MPI_Datatype) DEFINE_DIY_MPI_TYPE(MPI_Status) DEFINE_DIY_MPI_TYPE(MPI_Request) DEFINE_DIY_MPI_TYPE(MPI_Op) DEFINE_DIY_MPI_TYPE(MPI_File) -DEFINE_DIY_MPI_TYPE(MPI_Win) +DEFINE_DIY_MPI_TYPE_MOVE(MPI_Win) #undef DEFINE_DIY_MPI_TYPE +#undef DEFINE_DIY_MPI_TYPE_MOVE #undef ASSERT_MPI_TYPE_SIZE } diff --git a/include/vtkmdiy/mpi/no-mpi.hpp b/include/vtkmdiy/mpi/no-mpi.hpp index 8e7af241b..6809281ea 100644 --- a/include/vtkmdiy/mpi/no-mpi.hpp +++ b/include/vtkmdiy/mpi/no-mpi.hpp @@ -1,6 +1,7 @@ #ifndef VTKMDIY_MPI_NO_MPI_HPP #define VTKMDIY_MPI_NO_MPI_HPP +#include // std::assert #include // std::runtime_error @@ -75,7 +76,39 @@ static const int MPI_MODE_APPEND = 128; static const int MPI_MODE_SEQUENTIAL = 256; /* define window type */ -using MPI_Win = void*; +struct MPI_Win { + MPI_Win(): data_(0) {} + MPI_Win(void* data, bool owned = false): data_(uintptr_t(data) | (owned ? 0x1 : 0x0)) + { + // We assume that pointers have at least some higher-byte alignment. + assert(!(uintptr_t(data) & 0x1)); + } + void* data() const { return (void*)(data_ & ~0x1); } + bool owned() const { return data_ & 0x1; } + + // We cannot copy owned windows. + MPI_Win(MPI_Win const&) = delete; + MPI_Win& operator=(MPI_Win const&) = delete; + + // We cannot move owned windows (we don't know how to delete them in general). + MPI_Win(MPI_Win&& rhs): data_(rhs.data_) + { + rhs.data_ = 0; + } + MPI_Win& operator=(MPI_Win&& rhs) + { + if (this == &rhs) + return *this; + + data_ = rhs.data_; + rhs.data_ = 0; + + return *this; + } +private: + uintptr_t data_; +}; +#define MPI_WIN_NULL MPI_Win() /* window fence assertions */ static const int MPI_MODE_NOSTORE = 1; diff --git a/include/vtkmdiy/mpi/optional.hpp b/include/vtkmdiy/mpi/optional.hpp index aee4d269a..80eb63094 100644 --- a/include/vtkmdiy/mpi/optional.hpp +++ b/include/vtkmdiy/mpi/optional.hpp @@ -37,8 +37,8 @@ namespace mpi const void* address() const { return buf_; } private: + alignas(T) char buf_[sizeof(T)]; bool init_; - char buf_[sizeof(T)]; }; } } diff --git a/include/vtkmdiy/mpi/window.cpp b/include/vtkmdiy/mpi/window.cpp index 12b97bf7f..2805bd38d 100644 --- a/include/vtkmdiy/mpi/window.cpp +++ b/include/vtkmdiy/mpi/window.cpp @@ -22,6 +22,21 @@ EXPORT_MACRO const int nocheck = MPI_MODE_NOCHECK; namespace detail { +DIY_MPI_Win win_allocate(const communicator& comm, void** base, unsigned size, int disp) +{ +#if VTKMDIY_HAS_MPI + DIY_MPI_Win win; + MPI_Win_allocate(size, disp, MPI_INFO_NULL, mpi_cast(comm.handle()), base, &mpi_cast(win)); + return win; +#else + (void)comm; (void)disp; + *base = malloc(size); + auto mpi_win = MPI_Win(*base, true); + auto win = make_DIY_MPI_Win(std::move(mpi_win)); + return win; +#endif +} + DIY_MPI_Win win_create(const communicator& comm, void* base, unsigned size, int disp) { #if VTKMDIY_HAS_MPI @@ -30,7 +45,8 @@ DIY_MPI_Win win_create(const communicator& comm, void* base, unsigned size, int return win; #else (void)comm; (void)size; (void)disp; - auto win = make_DIY_MPI_Win(base); + auto mpi_win = MPI_Win(base); + auto win = make_DIY_MPI_Win(std::move(mpi_win)); return win; #endif } @@ -40,7 +56,9 @@ void win_free(DIY_MPI_Win& win) #if VTKMDIY_HAS_MPI MPI_Win_free(&mpi_cast(win)); #else - (void)win; + auto& mpi_win = mpi_cast(win); + if (mpi_win.owned()) + free(mpi_win.data()); #endif } @@ -49,7 +67,7 @@ void put(const DIY_MPI_Win& win, const void* data, int count, const datatype& ty #if VTKMDIY_HAS_MPI MPI_Put(data, count, mpi_cast(type.handle), rank, offset, count, mpi_cast(type.handle), mpi_cast(win)); #else - void* buffer = mpi_cast(win); + void* buffer = mpi_cast(win).data(); size_t size = mpi_cast(type.handle); std::copy_n(static_cast(data), size * static_cast(count), @@ -63,7 +81,7 @@ void get(const DIY_MPI_Win& win, void* data, int count, const datatype& type, in #if VTKMDIY_HAS_MPI MPI_Get(data, count, mpi_cast(type.handle), rank, offset, count, mpi_cast(type.handle), mpi_cast(win)); #else - const void* buffer = mpi_cast(win); + const void* buffer = mpi_cast(win).data(); size_t size = mpi_cast(type.handle); std::copy_n(static_cast(buffer) + (offset * size), size * static_cast(count), @@ -136,7 +154,7 @@ void fetch(const DIY_MPI_Win& win, void* result, const datatype& type, int rank, MPI_Fetch_and_op(nullptr, result, mpi_cast(type.handle), rank, offset, MPI_NO_OP, mpi_cast(win)); #else (void) rank; - const void* buffer = mpi_cast(win); + const void* buffer = mpi_cast(win).data(); size_t size = mpi_cast(type.handle); std::copy_n(static_cast(buffer) + (offset * size), size, @@ -150,7 +168,7 @@ void replace(const DIY_MPI_Win& win, const void* value, const datatype& type, in MPI_Fetch_and_op(value, nullptr, mpi_cast(type.handle), rank, offset, MPI_REPLACE, mpi_cast(win)); #else (void) rank; - void* buffer = mpi_cast(win); + void* buffer = mpi_cast(win).data(); size_t size = mpi_cast(type.handle); std::copy_n(static_cast(value), size, diff --git a/include/vtkmdiy/mpi/window.hpp b/include/vtkmdiy/mpi/window.hpp index 730d7c439..041fe2d44 100644 --- a/include/vtkmdiy/mpi/window.hpp +++ b/include/vtkmdiy/mpi/window.hpp @@ -22,6 +22,9 @@ VTKMDIY_MPI_EXPORT extern const int nocheck; namespace detail { +VTKMDIY_MPI_EXPORT_FUNCTION +DIY_MPI_Win win_allocate(const communicator& comm, void** base, unsigned size, int disp); + VTKMDIY_MPI_EXPORT_FUNCTION DIY_MPI_Win win_create(const communicator& comm, void* base, unsigned size, int disp); @@ -96,8 +99,8 @@ void flush_local_all(const DIY_MPI_Win& win); inline ~window(); // moving is Ok - window(window&&) = default; - window& operator=(window&&) = default; + inline window(window&&); + inline window& operator=(window&&); // cannot copy because of the buffer_ window(const window&) = delete; @@ -129,7 +132,7 @@ void flush_local_all(const DIY_MPI_Win& win); inline void flush_local_all(); private: - std::vector buffer_; + void* buffer_; int rank_; DIY_MPI_Win window_; }; @@ -140,16 +143,46 @@ void flush_local_all(const DIY_MPI_Win& win); template diy::mpi::window:: window(const diy::mpi::communicator& comm, unsigned size): - buffer_(size), rank_(comm.rank()) + buffer_(nullptr), rank_(comm.rank()) { - window_ = detail::win_create(comm, buffer_.data(), static_cast(buffer_.size()*sizeof(T)), static_cast(sizeof(T))); + window_ = detail::win_allocate(comm, &buffer_, static_cast(size*sizeof(T)), static_cast(sizeof(T))); } template diy::mpi::window:: ~window() { - detail::win_free(window_); + if (buffer_) + detail::win_free(window_); +} + +template +diy::mpi::window:: +window(window&& rhs): + buffer_(rhs.buffer_), rank_(rhs.rank_), window_(std::move(rhs.window_)) +{ + rhs.buffer_ = nullptr; + rhs.window_.reset(); +} + +template +diy::mpi::window& +diy::mpi::window:: +operator=(window&& rhs) +{ + if (this == &rhs) + return *this; + + if (buffer_) + detail::win_free(window_); + + buffer_ = rhs.buffer_; + rhs.buffer_ = nullptr; + rank_ = rhs.rank_; + window_ = std::move(rhs.window_); + rhs.window_.reset(); + + return *this; } template diff --git a/include/vtkmdiy/proxy.hpp b/include/vtkmdiy/proxy.hpp index 4de89d1cf..f843352d6 100644 --- a/include/vtkmdiy/proxy.hpp +++ b/include/vtkmdiy/proxy.hpp @@ -105,6 +105,12 @@ namespace diy void (*save)(BinaryBuffer&, const T&) = &::diy::save //!< optional serialization function ) const; + void inline enqueue_blob + (const BlockID& to, //!< target block (gid,proc) + const char* x, //!< pointer to the data + size_t n //!< size in data elements (eg. ints) + ) const; + //! Dequeue data whose size can be determined automatically (e.g., STL vector) and that was //! previously enqueued so that diy knows its size when it is received. //! In this case, diy will allocate the receive buffer; the user does not need to do so. @@ -142,6 +148,9 @@ namespace diy void (*load)(BinaryBuffer&, T&) = &::diy::load //!< optional serialization function ) const { dequeue(from.gid, x, n, load); } + BinaryBlob inline dequeue_blob + (int from) const; + template EnqueueIterator enqueuer(const T& x, void (*save)(BinaryBuffer&, const T&) = &::diy::save ) const @@ -347,5 +356,20 @@ dequeue(int from, T* x, size_t n, load(bb, x[i]); } +void +diy::Master::Proxy:: +enqueue_blob(const BlockID& to, const char* x, size_t n) const +{ + BinaryBuffer& bb = outgoing_[to]; + bb.save_binary_blob(x,n); +} + +diy::BinaryBlob +diy::Master::Proxy:: +dequeue_blob(int from) const +{ + BinaryBuffer& bb = incoming_[from]; + return bb.load_binary_blob(); +} #endif diff --git a/include/vtkmdiy/reduce.hpp b/include/vtkmdiy/reduce.hpp index 8f106ed49..b261ad5f8 100644 --- a/include/vtkmdiy/reduce.hpp +++ b/include/vtkmdiy/reduce.hpp @@ -138,7 +138,7 @@ void reduce(Master& master, //!< master object } } master.set_expected(expected); - master.flush(); + master.flush(false); } // final round log->debug("Round {}", round); diff --git a/include/vtkmdiy/serialization.hpp b/include/vtkmdiy/serialization.hpp index 992517608..0492fc32a 100644 --- a/include/vtkmdiy/serialization.hpp +++ b/include/vtkmdiy/serialization.hpp @@ -1,22 +1,30 @@ #ifndef VTKMDIY_SERIALIZATION_HPP #define VTKMDIY_SERIALIZATION_HPP -#include -#include +#include +#include +#include #include +#include #include #include -#include - #include +#include // this is used for a safety check for default serialization #include #include -#include // this is used for a safety check for default serialization - -#include +#include +#include namespace diy { + struct BinaryBlob + { + using Deleter = std::function; + using Pointer = std::unique_ptr; + Pointer pointer; + size_t size; + }; + //! A serialization buffer. \ingroup Serialization struct BinaryBuffer { @@ -25,10 +33,18 @@ namespace diy virtual inline void append_binary(const char* x, size_t count) =0; //!< append `count` bytes from `x` to end of buffer virtual void load_binary(char* x, size_t count) =0; //!< copy `count` bytes into `x` from the buffer virtual void load_binary_back(char* x, size_t count) =0; //!< copy `count` bytes into `x` from the back of the buffer + virtual char* grow(size_t count) =0; //!< allocate enough space for `count` bytes and return the pointer to the beginning + virtual char* advance(size_t count) =0; //!< advance buffer position by `count` bytes and return the pointer to the beginning + + virtual void save_binary_blob(const char*, size_t) =0; + virtual void save_binary_blob(const char*, size_t, BinaryBlob::Deleter) = 0; + virtual BinaryBlob load_binary_blob() =0; }; struct MemoryBuffer: public BinaryBuffer { + using Blob = BinaryBlob; + MemoryBuffer(size_t position_ = 0): position(position_) {} @@ -41,6 +57,13 @@ namespace diy virtual inline void append_binary(const char* x, size_t count) override; //!< append `count` bytes from `x` to end of buffer virtual inline void load_binary(char* x, size_t count) override; //!< copy `count` bytes into `x` from the buffer virtual inline void load_binary_back(char* x, size_t count) override; //!< copy `count` bytes into `x` from the back of the buffer + virtual inline char* grow(size_t count) override; //!< allocate enough space for `count` bytes and return the pointer to the beginning + virtual inline char* advance(size_t count) override; //!< advance buffer position by `count` bytes and return the pointer to the beginning + + virtual inline void save_binary_blob(const char* x, size_t count) override; + virtual inline void save_binary_blob(const char* x, size_t count, Blob::Deleter deleter) override; + virtual inline Blob load_binary_blob() override; + size_t nblobs() const { return blobs.size(); } void clear() { buffer.clear(); reset(); } void wipe() { std::vector().swap(buffer); reset(); } @@ -71,6 +94,9 @@ namespace diy size_t position; std::vector buffer; + + size_t blob_position = 0; + std::vector blobs; }; namespace detail @@ -140,7 +166,7 @@ namespace diy template void load_back(BinaryBuffer& bb, T& x) { bb.load_binary_back((char*) &x, sizeof(T)); } - //@} + //!@} namespace detail @@ -444,17 +470,7 @@ void diy::MemoryBuffer:: save_binary(const char* x, size_t count) { - if (position + count > buffer.capacity()) - { - double newsize = static_cast(position + count) * growth_multiplier(); // if we have to grow, grow geometrically - buffer.reserve(static_cast(newsize)); - } - - if (position + count > buffer.size()) - buffer.resize(position + count); - - std::copy_n(x, count, &buffer[position]); - position += count; + std::copy_n(x, count, grow(count)); } void @@ -509,6 +525,58 @@ load_binary_back(char* x, size_t count) buffer.resize(buffer.size() - count); } +char* +diy::MemoryBuffer:: +grow(size_t count) +{ + if (position + count > buffer.capacity()) + { + double newsize = static_cast(position + count) * growth_multiplier(); // if we have to grow, grow geometrically + buffer.reserve(static_cast(newsize)); + } + + if (position + count > buffer.size()) + buffer.resize(position + count); + + char* destination = &buffer[position]; + + position += count; + + return destination; +} + +char* +diy::MemoryBuffer:: +advance(size_t count) +{ + char* origin = &buffer[position]; + position += count; + return origin; +} + + +void +diy::MemoryBuffer:: +save_binary_blob(const char* x, size_t count) +{ + // empty deleter means we don't take ownership + save_binary_blob(x, count, [](const char[]) {}); +} + +void +diy::MemoryBuffer:: +save_binary_blob(const char* x, size_t count, Blob::Deleter deleter) +{ + blobs.emplace_back(Blob { Blob::Pointer {x, deleter}, count }); +} + +diy::MemoryBuffer::Blob +diy::MemoryBuffer:: +load_binary_blob() +{ + return std::move(blobs[blob_position++]); +} + void diy::MemoryBuffer:: copy(MemoryBuffer& from, MemoryBuffer& to) diff --git a/include/vtkmdiy/storage.hpp b/include/vtkmdiy/storage.hpp index cb541f546..f0e5bc984 100644 --- a/include/vtkmdiy/storage.hpp +++ b/include/vtkmdiy/storage.hpp @@ -15,8 +15,8 @@ namespace diy { namespace detail { - typedef void (*Save)(const void*, BinaryBuffer& buf); - typedef void (*Load)(void*, BinaryBuffer& buf); + using Save = std::function; + using Load = std::function; struct FileBuffer: public BinaryBuffer { @@ -34,6 +34,16 @@ namespace diy } virtual inline void load_binary(char* x, size_t count) override { auto n = fread(x, 1, count, file); VTKMDIY_UNUSED(n);} virtual inline void load_binary_back(char* x, size_t count) override { fseek(file, static_cast(tail), SEEK_END); auto n = fread(x, 1, count, file); tail += count; fseek(file, static_cast(head), SEEK_SET); VTKMDIY_UNUSED(n);} + virtual inline char* grow(size_t) override { throw std::runtime_error("Cannot grow a FileBuffer"); } + virtual inline char* advance(size_t) override { throw std::runtime_error("Cannot advance a FileBuffer"); } + + // TODO: for now, we just throw, but obviously it should be possile to store binary blobs in a file; might want to fall back + using Blob = BinaryBlob; + virtual inline void save_binary_blob(const char*, size_t) override { throw std::runtime_error("Cannot save binary blobs in a FileBuffer"); } + + virtual inline void save_binary_blob(const char*, size_t, Blob::Deleter) override { throw std::runtime_error("Cannot save binary blobs in a FileBuffer"); } + + virtual inline Blob load_binary_blob() override { throw std::runtime_error("Cannot load binary blobs from a FileBuffer"); } size_t size() const { return head; } diff --git a/include/vtkmdiy/thirdparty/chobo/small_vector.hpp b/include/vtkmdiy/thirdparty/itlib/small_vector.hpp similarity index 50% rename from include/vtkmdiy/thirdparty/chobo/small_vector.hpp rename to include/vtkmdiy/thirdparty/itlib/small_vector.hpp index 784534bbe..37386cbc6 100644 --- a/include/vtkmdiy/thirdparty/chobo/small_vector.hpp +++ b/include/vtkmdiy/thirdparty/itlib/small_vector.hpp @@ -1,9 +1,11 @@ -// chobo-small-vector v1.02 +// itlib-small-vector v1.04 // // std::vector-like class with a static buffer for initial capacity // +// SPDX-License-Identifier: MIT // MIT License: // Copyright(c) 2016-2018 Chobolabs Inc. +// Copyright(c) 2020-2022 Borislav Stanimirov // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files(the @@ -27,19 +29,20 @@ // // VERSION HISTORY // -// 1.02 (2018-04-24) Class inehrits from its allocator to make use of the -// empty base class optimization. -// emplace_back returns a reference to the inserted element -// as per the c++17 standard. -// 1.01 (2017-04-02) Fixed compilation error on (count, value) constructor and -// assign, and insert methods when count or value is 0 -// 1.00 (2016-11-08) First public release +// 1.04 (2022-04-14) Noxcept move construct and assign +// 1.03 (2021-10-05) Use allocator member instead of inheriting from allocator +// Allow compare with small_vector of different static_size +// Don't rely on operator!= from T. Use operator== instead +// 1.02 (2021-09-15) Bugfix! Fixed bad deallocation when reverting to +// static size on resize() +// 1.01 (2021-08-05) Bugfix! Fixed return value of erase +// 1.00 (2020-10-14) Rebranded release from chobo-small-vector // // // DOCUMENTATION // // Simply include this file wherever you need. -// It defines the class chobo::small_vector, which is a drop-in replacement of +// It defines the class itlib::small_vector, which is a drop-in replacement of // std::vector, but with an initial capacity as a template argument. // It gives you the benefits of using std::vector, at the cost of having a statically // allocated buffer for the initial capacity, which gives you cache-local data @@ -58,7 +61,7 @@ // // Example: // -// chobo::small_vector myvec; // a small_vector of size 0, initial capacity 4, and revert size 4 (smaller than 5) +// itlib::small_vector myvec; // a small_vector of size 0, initial capacity 4, and revert size 4 (smaller than 5) // myvec.resize(2); // vector is {0,0} in static buffer // myvec[1] = 11; // vector is {0,11} in static buffer // myvec.push_back(7); // vector is {0,11,7} in static buffer @@ -70,7 +73,7 @@ // // Reference: // -// chobo::small_vector is fully compatible with std::vector with +// itlib::small_vector is fully compatible with std::vector with // the following exceptions: // * when reducing the size with erase or resize the new size may fall below // RevertToStaticSize (if it is not 0). In such a case the vector will @@ -104,18 +107,18 @@ // called with an iterator that doesn't belong to the vector's current range. // For example: vec.erase(vec.end() + 1); // -// This is set by defining CHOBO_SMALL_VECTOR_ERROR_HANDLING to one of the +// This is set by defining ITLIB_SMALL_VECTOR_ERROR_HANDLING to one of the // following values: -// * CHOBO_SMALL_VECTOR_ERROR_HANDLING_NONE - no error handling. Crashes WILL +// * ITLIB_SMALL_VECTOR_ERROR_HANDLING_NONE - no error handling. Crashes WILL // ensue if the error is triggered. -// * CHOBO_SMALL_VECTOR_ERROR_HANDLING_THROW - std::out_of_range is thrown. -// * CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT - asserions are triggered. -// * CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW - combines assert and +// * ITLIB_SMALL_VECTOR_ERROR_HANDLING_THROW - std::out_of_range is thrown. +// * ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT - asserions are triggered. +// * ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW - combines assert and // throw to catch errors more easily in debug mode // // To set this setting by editing the file change the line: // ``` -// # define CHOBO_SMALL_VECTOR_ERROR_HANDLING CHOBO_SMALL_VECTOR_ERROR_HANDLING_THROW +// # define ITLIB_SMALL_VECTOR_ERROR_HANDLING ITLIB_SMALL_VECTOR_ERROR_HANDLING_THROW // ``` // to the default setting of your choice // @@ -124,15 +127,14 @@ // By default bounds checks are made in debug mode (via an asser) when accessing // elements (with `at` or `[]`). Iterators are not checked (yet...) // -// To disable them, you can define CHOBO_SMALL_VECTOR_NO_DEBUG_BOUNDS_CHECK +// To disable them, you can define ITLIB_SMALL_VECTOR_NO_DEBUG_BOUNDS_CHECK // before including the header. // // // TESTS // -// The tests are included in the header file and use doctest (https://github.com/onqtam/doctest). -// To run them, define CHOBO_SMALL_VECTOR_TEST_WITH_DOCTEST before including -// the header in a file which has doctest.h already included. +// You can find unit tests for small_vector in its official repo: +// https://github.com/iboB/itlib/blob/master/test/ // #pragma once @@ -140,58 +142,59 @@ #include #include -#define CHOBO_SMALL_VECTOR_ERROR_HANDLING_NONE 0 -#define CHOBO_SMALL_VECTOR_ERROR_HANDLING_THROW 1 -#define CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT 2 -#define CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW 3 +#define ITLIB_SMALL_VECTOR_ERROR_HANDLING_NONE 0 +#define ITLIB_SMALL_VECTOR_ERROR_HANDLING_THROW 1 +#define ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT 2 +#define ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW 3 -#if !defined(CHOBO_SMALL_VECTOR_ERROR_HANDLING) -# define CHOBO_SMALL_VECTOR_ERROR_HANDLING CHOBO_SMALL_VECTOR_ERROR_HANDLING_THROW +#if !defined(ITLIB_SMALL_VECTOR_ERROR_HANDLING) +# define ITLIB_SMALL_VECTOR_ERROR_HANDLING ITLIB_SMALL_VECTOR_ERROR_HANDLING_THROW #endif -#if CHOBO_SMALL_VECTOR_ERROR_HANDLING == CHOBO_SMALL_VECTOR_ERROR_HANDLING_NONE -# define _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(cond) -#elif CHOBO_SMALL_VECTOR_ERROR_HANDLING == CHOBO_SMALL_VECTOR_ERROR_HANDLING_THROW +#if ITLIB_SMALL_VECTOR_ERROR_HANDLING == ITLIB_SMALL_VECTOR_ERROR_HANDLING_NONE +# define I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(cond) +#elif ITLIB_SMALL_VECTOR_ERROR_HANDLING == ITLIB_SMALL_VECTOR_ERROR_HANDLING_THROW # include -# define _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(cond) if (cond) throw std::out_of_range("chobo::small_vector out of range") -#elif CHOBO_SMALL_VECTOR_ERROR_HANDLING == CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT +# define I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(cond) if (cond) throw std::out_of_range("itlib::small_vector out of range") +#elif ITLIB_SMALL_VECTOR_ERROR_HANDLING == ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT # include -# define _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(cond, rescue_return) assert(!(cond) && "chobo::small_vector out of range") -#elif CHOBO_SMALL_VECTOR_ERROR_HANDLING == CHOBO_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW +# define I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(cond, rescue_return) assert(!(cond) && "itlib::small_vector out of range") +#elif ITLIB_SMALL_VECTOR_ERROR_HANDLING == ITLIB_SMALL_VECTOR_ERROR_HANDLING_ASSERT_AND_THROW # include # include -# define _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(cond, rescue_return) \ - do { if (cond) { assert(false && "chobo::small_vector out of range"); throw std::out_of_range("chobo::small_vector out of range"); } } while(false) +# define I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(cond, rescue_return) \ + do { if (cond) { assert(false && "itlib::small_vector out of range"); throw std::out_of_range("itlib::small_vector out of range"); } } while(false) #else -#error "Unknown CHOBO_SMALL_VECTOR_ERRROR_HANDLING" +#error "Unknown ITLIB_SMALL_VECTOR_ERRROR_HANDLING" #endif -#if defined(CHOBO_SMALL_VECTOR_NO_DEBUG_BOUNDS_CHECK) -# define _CHOBO_SMALL_VECTOR_BOUNDS_CHECK(i) +#if defined(ITLIB_SMALL_VECTOR_NO_DEBUG_BOUNDS_CHECK) +# define I_ITLIB_SMALL_VECTOR_BOUNDS_CHECK(i) #else # include -# define _CHOBO_SMALL_VECTOR_BOUNDS_CHECK(i) assert((i) < this->size()) +# define I_ITLIB_SMALL_VECTOR_BOUNDS_CHECK(i) assert((i) < this->size()) #endif -namespace chobo +namespace itlib { template> -struct small_vector: Alloc +struct small_vector { - static_assert(RevertToStaticSize <= StaticCapacity + 1, "chobo::small_vector: the revert-to-static size shouldn't exceed the static capacity by more than one"); + static_assert(RevertToStaticSize <= StaticCapacity + 1, "itlib::small_vector: the revert-to-static size shouldn't exceed the static capacity by more than one"); + using atraits = std::allocator_traits; public: using allocator_type = Alloc; - using value_type = typename Alloc::value_type; - using size_type = typename Alloc::size_type; - using difference_type = typename Alloc::difference_type; - using reference = typename Alloc::reference; - using const_reference = typename Alloc::const_reference; - using pointer = typename Alloc::pointer; - using const_pointer = typename Alloc::const_pointer; + using value_type = typename atraits::value_type; + using size_type = typename atraits::size_type; + using difference_type = typename atraits::difference_type; + using reference = T&; + using const_reference = const T&; + using pointer = typename atraits::pointer; + using const_pointer = typename atraits::const_pointer; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; @@ -205,7 +208,7 @@ public: {} small_vector(const Alloc& alloc) - : Alloc(alloc) + : m_alloc(alloc) , m_capacity(StaticCapacity) , m_dynamic_capacity(0) , m_dynamic_data(nullptr) @@ -239,18 +242,18 @@ public: } small_vector(const small_vector& v) - : small_vector(v, std::allocator_traits::select_on_container_copy_construction(v.get_allocator())) + : small_vector(v, atraits::select_on_container_copy_construction(v.get_allocator())) {} small_vector(const small_vector& v, const Alloc& alloc) - : Alloc(alloc) + : m_alloc(alloc) , m_dynamic_capacity(0) , m_dynamic_data(nullptr) { if (v.size() > StaticCapacity) { m_dynamic_capacity = v.size(); - m_begin = m_end = m_dynamic_data = get_alloc().allocate(m_dynamic_capacity); + m_begin = m_end = m_dynamic_data = atraits::allocate(get_alloc(), m_dynamic_capacity); m_capacity = v.size(); } else @@ -261,13 +264,13 @@ public: for (auto p = v.m_begin; p != v.m_end; ++p) { - get_alloc().construct(m_end, *p); + atraits::construct(get_alloc(), m_end, *p); ++m_end; } } - small_vector(small_vector&& v) - : Alloc(std::move(v.get_alloc())) + small_vector(small_vector&& v) noexcept + : m_alloc(std::move(v.get_alloc())) , m_capacity(v.m_capacity) , m_dynamic_capacity(v.m_dynamic_capacity) , m_dynamic_data(v.m_dynamic_data) @@ -277,7 +280,7 @@ public: m_begin = m_end = static_begin_ptr(); for (auto p = v.m_begin; p != v.m_end; ++p) { - get_alloc().construct(m_end, std::move(*p)); + atraits::construct(get_alloc(), m_end, std::move(*p)); ++m_end; } @@ -301,7 +304,7 @@ public: if (m_dynamic_data) { - get_alloc().deallocate(m_dynamic_data, m_dynamic_capacity); + atraits::deallocate(get_alloc(), m_dynamic_data, m_dynamic_capacity); } } @@ -319,7 +322,7 @@ public: for (auto p = v.m_begin; p != v.m_end; ++p) { - get_alloc().construct(m_end, *p); + atraits::construct(get_alloc(), m_end, *p); ++m_end; } @@ -328,7 +331,7 @@ public: return *this; } - small_vector& operator=(small_vector&& v) + small_vector& operator=(small_vector&& v) noexcept { clear(); @@ -342,7 +345,7 @@ public: m_begin = m_end = static_begin_ptr(); for (auto p = v.m_begin; p != v.m_end; ++p) { - get_alloc().construct(m_end, std::move(*p)); + atraits::construct(get_alloc(), m_end, std::move(*p)); ++m_end; } @@ -388,13 +391,13 @@ public: const_reference at(size_type i) const { - _CHOBO_SMALL_VECTOR_BOUNDS_CHECK(i); + I_ITLIB_SMALL_VECTOR_BOUNDS_CHECK(i); return *(m_begin + i); } reference at(size_type i) { - _CHOBO_SMALL_VECTOR_BOUNDS_CHECK(i); + I_ITLIB_SMALL_VECTOR_BOUNDS_CHECK(i); return *(m_begin + i); } @@ -512,7 +515,7 @@ public: size_t max_size() const noexcept { - return get_alloc().max_size(); + return atraits::max_size(); } void reserve(size_type new_cap) @@ -534,19 +537,19 @@ public: // now we need to transfer the existing elements into the new buffer for (size_type i = 0; i < s; ++i) { - get_alloc().construct(new_buf + i, std::move(*(m_begin + i))); + atraits::construct(get_alloc(), new_buf + i, std::move(*(m_begin + i))); } // free old elements for (size_type i = 0; i < s; ++i) { - get_alloc().destroy(m_begin + i); + atraits::destroy(get_alloc(), m_begin + i); } if (m_begin != static_begin_ptr()) { // we've moved from dyn to dyn memory, so deallocate the old one - get_alloc().deallocate(m_begin, m_capacity); + atraits::deallocate(get_alloc(), m_begin, m_capacity); } m_begin = new_buf; @@ -577,18 +580,18 @@ public: else { // alloc new smaller buffer - m_begin = m_end = get_alloc().allocate(s); + m_begin = m_end = atraits::allocate(get_alloc(), s); m_capacity = s; } for (auto p = m_dynamic_data; p != old_end; ++p) { - get_alloc().construct(m_end, std::move(*p)); + atraits::construct(get_alloc(), m_end, std::move(*p)); ++m_end; - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } - get_alloc().deallocate(m_dynamic_data, m_dynamic_capacity); + atraits::deallocate(get_alloc(), m_dynamic_data, m_dynamic_capacity); m_dynamic_data = nullptr; m_dynamic_capacity = 0; } @@ -605,9 +608,9 @@ public: m_capacity = StaticCapacity; for (auto p = m_dynamic_data; p != old_end; ++p) { - get_alloc().construct(m_end, std::move(*p)); + atraits::construct(get_alloc(), m_end, std::move(*p)); ++m_end; - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } } @@ -616,7 +619,7 @@ public: { for (auto p = m_begin; p != m_end; ++p) { - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } if (RevertToStaticSize > 0) @@ -633,14 +636,14 @@ public: iterator insert(const_iterator position, const value_type& val) { auto pos = grow_at(position, 1); - get_alloc().construct(pos, val); + atraits::construct(get_alloc(), pos, val); return pos; } iterator insert(const_iterator position, value_type&& val) { auto pos = grow_at(position, 1); - get_alloc().construct(pos, std::move(val)); + atraits::construct(get_alloc(), pos, std::move(val)); return pos; } @@ -649,7 +652,7 @@ public: auto pos = grow_at(position, count); for (size_type i = 0; i < count; ++i) { - get_alloc().construct(pos + i, val); + atraits::construct(get_alloc(), pos + i, val); } return pos; } @@ -662,7 +665,7 @@ public: auto np = pos; for (auto p = first; p != last; ++p, ++np) { - get_alloc().construct(np, *p); + atraits::construct(get_alloc(), np, *p); } return pos; } @@ -673,7 +676,7 @@ public: size_type i = 0; for (auto& elem : ilist) { - get_alloc().construct(pos + i, elem); + atraits::construct(get_alloc(), pos + i, elem); ++i; } return pos; @@ -683,7 +686,7 @@ public: iterator emplace(const_iterator position, Args&&... args) { auto pos = grow_at(position, 1); - get_alloc().construct(pos, std::forward(args)...); + atraits::construct(get_alloc(), pos, std::forward(args)...); return pos; } @@ -694,27 +697,27 @@ public: iterator erase(const_iterator first, const_iterator last) { - _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(first > last); + I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(first > last); return shrink_at(first, last - first); } void push_back(const_reference val) { auto pos = grow_at(m_end, 1); - get_alloc().construct(pos, val); + atraits::construct(get_alloc(), pos, val); } void push_back(T&& val) { auto pos = grow_at(m_end, 1); - get_alloc().construct(pos, std::move(val)); + atraits::construct(get_alloc(), pos, std::move(val)); } template reference emplace_back(Args&&... args) { auto pos = grow_at(m_end, 1); - get_alloc().construct(pos, std::forward(args)...); + atraits::construct(get_alloc(), pos, std::forward(args)...); return *pos; } @@ -735,12 +738,12 @@ public: while (m_end > new_end) { - get_alloc().destroy(--m_end); + atraits::destroy(get_alloc(), --m_end); } while (new_end > m_end) { - get_alloc().construct(m_end++, v); + atraits::construct(get_alloc(), m_end++, v); } } else @@ -752,25 +755,19 @@ public: for (size_type i = 0; i < num_transfer; ++i) { - get_alloc().construct(new_buf + i, std::move(*(m_begin + i))); + atraits::construct(get_alloc(), new_buf + i, std::move(*(m_begin + i))); } // free obsoletes for (size_type i = 0; i < s; ++i) { - get_alloc().destroy(m_begin + i); + atraits::destroy(get_alloc(), m_begin + i); } // construct new elements for (size_type i = num_transfer; i < n; ++i) { - get_alloc().construct(new_buf + i, v); - } - - if (m_begin != static_begin_ptr()) - { - // we've moved from dyn to dyn memory, so deallocate the old one - get_alloc().deallocate(m_begin, m_capacity); + atraits::construct(get_alloc(), new_buf + i, v); } if (new_buf == static_begin_ptr()) @@ -779,6 +776,11 @@ public: } else { + if (m_begin != static_begin_ptr()) + { + // we've moved from dyn to dyn memory, so deallocate the old one + atraits::deallocate(get_alloc(), m_begin, m_capacity); + } m_capacity = m_dynamic_capacity; } @@ -799,12 +801,12 @@ public: while (m_end > new_end) { - get_alloc().destroy(--m_end); + atraits::destroy(get_alloc(), --m_end); } while (new_end > m_end) { - get_alloc().construct(m_end++); + atraits::construct(get_alloc(), m_end++); } } else @@ -816,25 +818,19 @@ public: for (size_type i = 0; i < num_transfer; ++i) { - get_alloc().construct(new_buf + i, std::move(*(m_begin + i))); + atraits::construct(get_alloc(), new_buf + i, std::move(*(m_begin + i))); } // free obsoletes - for (size_type i = 0; i < n; ++i) + for (size_type i = 0; i < s; ++i) { - get_alloc().destroy(m_begin + i); + atraits::destroy(get_alloc(), m_begin + i); } // construct new elements - for (size_type i = num_transfer; i < s; ++i) + for (size_type i = num_transfer; i < n; ++i) { - get_alloc().construct(new_buf + i); - } - - if (m_begin != static_begin_ptr()) - { - // we've moved from dyn to dyn memory, so deallocate the old one - get_alloc().deallocate(m_begin, m_capacity); + atraits::construct(get_alloc(), new_buf + i); } if (new_buf == static_begin_ptr()) @@ -843,6 +839,11 @@ public: } else { + if (m_begin != static_begin_ptr()) + { + // we've moved from dyn to dyn memory, so deallocate the old one + atraits::deallocate(get_alloc(), m_begin, m_capacity); + } m_capacity = m_dynamic_capacity; } @@ -864,7 +865,7 @@ private: { auto position = const_cast(cp); - _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(position < m_begin || position > m_end); + I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(position < m_begin || position > m_end); const auto s = size(); auto new_buf = choose_data(s + num); @@ -877,8 +878,8 @@ private: for (auto p = m_end - num - 1; p >= position; --p) { - get_alloc().construct(p + num, std::move(*p)); - get_alloc().destroy(p); + atraits::construct(get_alloc(), p + num, std::move(*p)); + atraits::destroy(get_alloc(), p); } return position; @@ -894,25 +895,25 @@ private: for (; np != position; ++p, ++np) { - get_alloc().construct(np, std::move(*p)); + atraits::construct(get_alloc(), np, std::move(*p)); } np += num; for (; p != m_end; ++p, ++np) { - get_alloc().construct(np, std::move(*p)); + atraits::construct(get_alloc(), np, std::move(*p)); } // destroy old for (p = m_begin; p != m_end; ++p) { - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } if (m_begin != static_begin_ptr()) { // we've moved from dyn to dyn memory, so deallocate the old one - get_alloc().deallocate(m_begin, m_capacity); + atraits::deallocate(get_alloc(), m_begin, m_capacity); } m_capacity = m_dynamic_capacity; @@ -928,7 +929,7 @@ private: { auto position = const_cast(cp); - _CHOBO_SMALL_VECTOR_OUT_OF_RANGE_IF(position < m_begin || position > m_end || position + num > m_end); + I_ITLIB_SMALL_VECTOR_OUT_OF_RANGE_IF(position < m_begin || position > m_end || position + num > m_end); const auto s = size(); if (s - num == 0) @@ -945,13 +946,13 @@ private: for (auto p = position, np = position + num; np != m_end; ++p, ++np) { - get_alloc().destroy(p); - get_alloc().construct(p, std::move(*np)); + atraits::destroy(get_alloc(), p); + atraits::construct(get_alloc(), p, std::move(*np)); } for (auto p = m_end - num; p != m_end; ++p) { - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } m_end -= num; @@ -967,19 +968,19 @@ private: auto p = m_begin, np = new_buf; for (; p != position; ++p, ++np) { - get_alloc().construct(np, std::move(*p)); - get_alloc().destroy(p); + atraits::construct(get_alloc(), np, std::move(*p)); + atraits::destroy(get_alloc(), p); } for (; p != position + num; ++p) { - get_alloc().destroy(p); + atraits::destroy(get_alloc(), p); } for (; np != new_buf + s - num; ++p, ++np) { - get_alloc().construct(np, std::move(*p)); - get_alloc().destroy(p); + atraits::construct(get_alloc(), np, std::move(*p)); + atraits::destroy(get_alloc(), p); } position = new_buf + (position - m_begin); @@ -987,7 +988,7 @@ private: m_end = np; } - return ++position; + return position; } void assign_impl(size_type count, const T& value) @@ -998,7 +999,7 @@ private: m_begin = m_end = choose_data(count); for (size_type i = 0; i < count; ++i) { - get_alloc().construct(m_end, value); + atraits::construct(get_alloc(), m_end, value); ++m_end; } @@ -1014,7 +1015,7 @@ private: m_begin = m_end = choose_data(last - first); for (auto p = first; p != last; ++p) { - get_alloc().construct(m_end, *p); + atraits::construct(get_alloc(), m_end, *p); ++m_end; } @@ -1029,7 +1030,7 @@ private: m_begin = m_end = choose_data(ilist.size()); for (auto& elem : ilist) { - get_alloc().construct(m_end, elem); + atraits::construct(get_alloc(), m_end, elem); ++m_end; } @@ -1064,7 +1065,7 @@ private: m_dynamic_capacity /= 2; } - m_dynamic_data = get_alloc().allocate(m_dynamic_capacity); + m_dynamic_data = atraits::allocate(get_alloc(), m_dynamic_capacity); return m_dynamic_data; } else if (desired_capacity < RevertToStaticSize) @@ -1093,11 +1094,11 @@ private: // we don't have anything to destroy, so we can also deallocate the buffer if (m_dynamic_data) { - get_alloc().deallocate(m_dynamic_data, m_dynamic_capacity); + atraits::deallocate(get_alloc(), m_dynamic_data, m_dynamic_capacity); } m_dynamic_capacity = desired_capacity; - m_dynamic_data = get_alloc().allocate(m_dynamic_capacity); + m_dynamic_data = atraits::allocate(get_alloc(), m_dynamic_capacity); } return m_dynamic_data; @@ -1110,8 +1111,10 @@ private: } } - allocator_type& get_alloc() { return static_cast(*this); } - const allocator_type& get_alloc() const { return static_cast(*this); } + allocator_type& get_alloc() { return m_alloc; } + const allocator_type& get_alloc() const { return m_alloc; } + + allocator_type m_alloc; pointer m_begin; pointer m_end; @@ -1123,9 +1126,12 @@ private: pointer m_dynamic_data; }; -template -bool operator==(const small_vector& a, - const small_vector& b) +template +bool operator==(const small_vector& a, + const small_vector& b) { if (a.size() != b.size()) { @@ -1134,583 +1140,22 @@ bool operator==(const small_vector for (size_t i = 0; i < a.size(); ++i) { - if (a[i] != b[i]) + if (!(a[i] == b[i])) return false; } return true; } -template -bool operator!=(const small_vector& a, - const small_vector& b) +template +bool operator!=(const small_vector& a, + const small_vector& b) + { - if (a.size() != b.size()) - { - return true; - } - - for (size_t i = 0; i < a.size(); ++i) - { - if (a[i] != b[i]) - return true; - } - - return false; + return !operator==(a, b); } } - - -#if defined(CHOBO_SMALL_VECTOR_TEST_WITH_DOCTEST) - -#include -#include - -namespace chobo_small_vector_test -{ - -size_t allocations = 0; -size_t deallocations = 0; -size_t allocated_bytes = 0; -size_t deallocated_bytes = 0; -size_t constructions = 0; -size_t destructions = 0; - -template -class counting_allocator : public std::allocator -{ -public: - typedef std::allocator super; - - T* allocate(size_t n, std::allocator::const_pointer hint = 0) - { - ++allocations; - allocated_bytes += n * sizeof(T); - return super::allocate(n, hint); - } - - void deallocate(T* p, size_t n) - { - ++deallocations; - deallocated_bytes += n * sizeof(T); - return super::deallocate(p, n); - } - - template< class U, class... Args > - void construct(U* p, Args&&... args) - { - ++constructions; - return super::construct(p, std::forward(args)...); - } - - template< class U > - void destroy(U* p) - { - ++destructions; - return super::destroy(p); - } -}; -} - -TEST_CASE("[small_vector] static") -{ - using namespace chobo; - using namespace chobo_small_vector_test; - using namespace std; - - static_assert(sizeof(small_vector) - sizeof(small_vector) == sizeof(void*) * 7, "small_vector needs to have a static buffer"); - { - small_vector> ivec; - CHECK(ivec.size() == 0); - CHECK(ivec.capacity() == 10); - CHECK(ivec.begin() == ivec.end()); - CHECK(ivec.cbegin() == ivec.cend()); - CHECK(ivec.empty()); - - auto d = ivec.data(); - ivec.reserve(9); - CHECK(ivec.capacity() == 10); - CHECK(d == ivec.data()); - - ivec.resize(2, 8); - CHECK(ivec.size() == 2); - CHECK(ivec.front() == 8); - CHECK(ivec.back() == 8); - CHECK(d == ivec.data()); - - ivec.clear(); - CHECK(ivec.size() == 0); - CHECK(ivec.capacity() == 10); - CHECK(ivec.begin() == ivec.end()); - CHECK(ivec.cbegin() == ivec.cend()); - CHECK(ivec.empty()); - CHECK(d == ivec.data()); - - ivec.push_back(5); - CHECK(ivec.size() == 1); - CHECK(ivec[0] == 5); - auto it = ivec.begin(); - CHECK(it == ivec.data()); - CHECK(it == ivec.cbegin()); - CHECK(*it == 5); - ++it; - CHECK(it == ivec.end()); - CHECK(it == ivec.cend()); - - auto& back = ivec.emplace_back(3); - CHECK(ivec.size() == 2); - auto rit = ivec.rbegin(); - CHECK(*rit == 3); - ++rit; - *rit = 12; - ++rit; - CHECK(rit == ivec.rend()); - CHECK(rit == ivec.crend()); - CHECK(ivec.front() == 12); - CHECK(ivec.back() == 3); - CHECK(back == 3); - CHECK(&back == &ivec.back()); - - ivec.insert(ivec.begin(), 53); - ivec.insert(ivec.begin() + 2, 90); - ivec.insert(ivec.begin() + 4, 17); - ivec.insert(ivec.end(), 6); - ivec.insert(ivec.begin(), { 1, 2 }); - - int ints[] = { 1, 2, 53, 12, 90, 3, 17, 6 }; - CHECK(ivec.size() == 8); - CHECK(memcmp(ivec.data(), ints, sizeof(ints)) == 0); - - ivec.shrink_to_fit(); - CHECK(ivec.size() == 8); - CHECK(ivec.capacity() == 10); - CHECK(d == ivec.data()); - - ivec.revert_to_static(); - CHECK(ivec.size() == 8); - CHECK(ivec.capacity() == 10); - CHECK(d == ivec.data()); - - ivec.pop_back(); - CHECK(ivec.size() == 7); - CHECK(memcmp(ivec.data(), ints, sizeof(ints) - sizeof(int)) == 0); - - ivec.resize(8); - CHECK(ivec.size() == 8); - ints[7] = 0; - CHECK(memcmp(ivec.data(), ints, sizeof(ints)) == 0); - - const small_vector> ivec2 = { 1, 2, 3, 4 }; - CHECK(ivec2.size() == 4); - CHECK(*ivec2.begin() == 1); - CHECK(ivec2[1] == 2); - CHECK(ivec2.at(2) == 3); - CHECK(*ivec2.rbegin() == 4); - - ivec.erase(ivec.begin()); - CHECK(ivec.size() == 7); - CHECK(ivec.front() == 2); - CHECK(memcmp(ivec.data(), ints + 1, ivec.size() * sizeof(int)) == 0); - - ivec.erase(ivec.begin() + 2, ivec.begin() + 4); - CHECK(ivec.size() == 5); - CHECK(ivec[3] == 17); - - small_vector> svec; - svec.assign({ "as", "df" }); - CHECK(svec.size() == 2); - string s1 = "the quick brown fox jumped over the lazy dog 1234567890"; - auto& rs = svec.emplace_back(s1); - CHECK(svec.back() == s1); - CHECK(rs == s1); - CHECK(&rs == &svec.back()); - - auto svec1 = svec; - CHECK(svec1 == svec); - - const void* cstr = svec.back().c_str(); - auto svec2 = std::move(svec); - CHECK(svec2.size() == 3); - CHECK(svec2.back() == s1); - - CHECK(svec.empty()); - CHECK(svec2.back().c_str() == cstr); - - svec = std::move(svec2); - CHECK(svec2.empty()); - CHECK(svec.back().c_str() == cstr); - - svec2 = svec; - CHECK(svec2.back() == s1); - CHECK(svec.back() == s1); - CHECK(svec == svec2); - - svec.insert(svec.begin(), s1); - CHECK(svec.size() == 4); - CHECK(svec.back().c_str() == cstr); - CHECK(svec.front() == svec.back()); - - cstr = s1.c_str(); - svec.emplace(svec.begin() + 2, std::move(s1)); - CHECK(svec.size() == 5); - CHECK(svec.front() == svec[2]); - CHECK(svec[2].c_str() == cstr); - - svec.clear(); - CHECK(svec.empty()); - svec2.clear(); - CHECK(svec2.empty()); - CHECK(svec == svec2); - - svec.resize(svec.capacity()); - CHECK(svec.size() == svec.capacity()); - - for (auto& s : svec) - { - CHECK(s.empty()); - } - - s1 = "asdf"; - small_vector> cvec(s1.begin(), s1.end()); - CHECK(cvec.size() == 4); - CHECK(cvec.front() == 'a'); - CHECK(cvec.back() == 'f'); - - cvec.clear(); - CHECK(cvec.size() == 0); - CHECK(cvec.empty()); - - s1 = "baz"; - cvec.assign(s1.begin(), s1.end()); - CHECK(cvec.size() == 3); - CHECK(cvec.front() == 'b'); - CHECK(cvec.back() == 'z'); - - // 0 is implicitly castable to nullptr_t which can be an iterator in our case - small_vector nullptr_test(2, 0); - CHECK(nullptr_test.size() == 2); - CHECK(nullptr_test.front() == 0); - CHECK(nullptr_test.back() == 0); - - nullptr_test.assign(3, 0); - CHECK(nullptr_test.size() == 3); - CHECK(nullptr_test.front() == 0); - CHECK(nullptr_test.back() == 0); - - nullptr_test.insert(nullptr_test.begin(), 1, 0); - CHECK(nullptr_test.size() == 4); - CHECK(nullptr_test.front() == 0); - } - - CHECK(allocations == 0); - CHECK(deallocations == 0); - CHECK(allocated_bytes == 0); - CHECK(deallocated_bytes == 0); - CHECK(constructions == destructions); - - constructions = destructions = 0; -} - - -TEST_CASE("[small_vector] dynamic") -{ - using namespace chobo; - using namespace chobo_small_vector_test; - using namespace std; - { - small_vector> ivec; - CHECK(ivec.size() == 0); - CHECK(ivec.capacity() == 1); - CHECK(ivec.begin() == ivec.end()); - CHECK(ivec.cbegin() == ivec.cend()); - CHECK(ivec.empty()); - - auto d = ivec.data(); - ivec.reserve(2); - CHECK(ivec.capacity() == 2); - CHECK(d != ivec.data()); - CHECK(allocations == 1); - - ivec.resize(3, 8); - CHECK(ivec.capacity() == 3); - CHECK(ivec.size() == 3); - CHECK(ivec.front() == 8); - CHECK(ivec.back() == 8); - CHECK(d != ivec.data()); - CHECK(allocations == 2); - - ivec.clear(); - CHECK(ivec.size() == 0); - CHECK(ivec.capacity() == 3); - CHECK(d != ivec.data()); - CHECK(ivec.begin() == ivec.end()); - CHECK(ivec.cbegin() == ivec.cend()); - CHECK(ivec.empty()); - - ivec.push_back(5); - CHECK(ivec.size() == 1); - CHECK(ivec[0] == 5); - auto it = ivec.begin(); - CHECK(it == ivec.data()); - CHECK(it == ivec.cbegin()); - CHECK(*it == 5); - ++it; - CHECK(it == ivec.end()); - CHECK(it == ivec.cend()); - - auto& back = ivec.emplace_back(3); - CHECK(ivec.size() == 2); - auto rit = ivec.rbegin(); - CHECK(*rit == 3); - ++rit; - *rit = 12; - ++rit; - CHECK(rit == ivec.rend()); - CHECK(rit == ivec.crend()); - CHECK(ivec.front() == 12); - CHECK(ivec.back() == 3); - CHECK(back == 3); - CHECK(&back == &ivec.back()); - - ivec.insert(ivec.begin(), 53); - CHECK(ivec.capacity() == 3); - - ivec.insert(ivec.begin() + 2, 90); - ivec.insert(ivec.begin() + 4, 17); - ivec.insert(ivec.end(), 6); - ivec.insert(ivec.begin(), { 1, 2 }); - - int ints[] = { 1, 2, 53, 12, 90, 3, 17, 6 }; - CHECK(ivec.capacity() >= 8); - CHECK(ivec.size() == 8); - CHECK(memcmp(ivec.data(), ints, sizeof(ints)) == 0); - - ivec.pop_back(); - CHECK(ivec.size() == 7); - CHECK(memcmp(ivec.data(), ints, sizeof(ints) - sizeof(int)) == 0); - - ivec.resize(8); - CHECK(ivec.size() == 8); - ints[7] = 0; - CHECK(memcmp(ivec.data(), ints, sizeof(ints)) == 0); - - const small_vector> ivec2 = { 1, 2, 3, 4 }; - CHECK(ivec2.size() == 4); - CHECK(*ivec2.begin() == 1); - CHECK(ivec2[1] == 2); - CHECK(ivec2.at(2) == 3); - CHECK(*ivec2.rbegin() == 4); - - ivec.erase(ivec.begin()); - CHECK(ivec.size() == 7); - CHECK(ivec.front() == 2); - CHECK(memcmp(ivec.data(), ints + 1, ivec.size() * sizeof(int)) == 0); - - ivec.erase(ivec.begin() + 2, ivec.begin() + 4); - CHECK(ivec.size() == 5); - CHECK(ivec[3] == 17); - - small_vector> svec; - svec.assign({ "as", "df" }); - CHECK(svec.size() == 2); - string s1 = "the quick brown fox jumped over the lazy dog 1234567890"; - auto& rs = svec.emplace_back(s1); - CHECK(svec.back() == s1); - CHECK(rs == s1); - CHECK(&rs == &svec.back()); - - auto svec1 = svec; - CHECK(svec1 == svec); - - const void* cstr = svec.back().c_str(); - auto svec2 = std::move(svec); - CHECK(svec2.size() == 3); - CHECK(svec2.back() == s1); - - CHECK(svec.empty()); - CHECK(svec2.back().c_str() == cstr); - - svec = std::move(svec2); - CHECK(svec2.empty()); - CHECK(svec.back().c_str() == cstr); - - svec2 = svec; - CHECK(svec2.back() == s1); - CHECK(svec.back() == s1); - CHECK(svec == svec2); - - svec.insert(svec.begin(), s1); - CHECK(svec.size() == 4); - CHECK(svec.back().c_str() == cstr); - CHECK(svec.front() == svec.back()); - - cstr = s1.c_str(); - svec.emplace(svec.begin() + 2, std::move(s1)); - CHECK(svec.size() == 5); - CHECK(svec.front() == svec[2]); - CHECK(svec[2].c_str() == cstr); - - svec.clear(); - CHECK(svec.empty()); - svec2.clear(); - CHECK(svec2.empty()); - CHECK(svec == svec2); - - svec.resize(svec.capacity()); - CHECK(svec.size() == svec.capacity()); - - for (auto& s : svec) - { - CHECK(s.empty()); - } - - s1 = "asdf"; - small_vector> cvec(s1.begin(), s1.end()); - CHECK(cvec.size() == 4); - CHECK(cvec.front() == 'a'); - CHECK(cvec.back() == 'f'); - - cvec.clear(); - CHECK(cvec.size() == 0); - CHECK(cvec.empty()); - - s1 = "baz"; - cvec.assign(s1.begin(), s1.end()); - CHECK(cvec.size() == 3); - CHECK(cvec.front() == 'b'); - CHECK(cvec.back() == 'z'); - } - - CHECK(allocations == deallocations); - CHECK(allocated_bytes == deallocated_bytes); - CHECK(constructions == destructions); - - allocations = deallocations = allocated_bytes = deallocated_bytes = constructions = destructions = 0; -} - -TEST_CASE("[small_vector] static-dynamic") -{ - using namespace chobo; - using namespace chobo_small_vector_test; - using namespace std; - - { - small_vector> ivec; - auto d = ivec.data(); - ivec.reserve(20); - CHECK(ivec.data() == d); - - ivec.push_back(1); - ivec.push_back(2); - ivec.push_back(3); - - CHECK(ivec.data() == d); - - ivec.insert(ivec.end(), 3u, 8); - - CHECK(ivec.size() == 6); - CHECK(ivec.capacity() == 20); - - auto dd = ivec.data(); - - ivec.erase(ivec.begin(), ivec.begin() + 6); - CHECK(ivec.data() == d); - CHECK(ivec.empty()); - - ivec.resize(19, 11); - CHECK(ivec.size() == 19); - CHECK(ivec.capacity() == 20); - CHECK(ivec.data() == dd); - - ivec.resize(4); - CHECK(ivec.size() == 4); - CHECK(ivec.capacity() == 20); - CHECK(ivec.data() == dd); - - ivec.revert_to_static(); - CHECK(ivec.size() == 4); - CHECK(ivec.capacity() == 5); - CHECK(ivec.data() == d); - - ivec.reserve(10); - CHECK(ivec.size() == 4); - CHECK(ivec.capacity() == 20); - CHECK(ivec.data() == dd); - - ivec.shrink_to_fit(); - CHECK(ivec.size() == 4); - CHECK(ivec.capacity() == 5); - CHECK(ivec.data() == d); - - ivec.reserve(10); - CHECK(ivec.size() == 4); - CHECK(ivec.capacity() == 10); - CHECK(ivec.data() != d); - - dd = ivec.data(); - ivec.insert(ivec.begin() + 3, 5u, 88); - CHECK(ivec.size() == 9); - CHECK(ivec.capacity() == 10); - CHECK(ivec.data() == dd); - CHECK(ivec[2] == 11); - CHECK(ivec[7] == 88); - CHECK(ivec[8] == 11); - - small_vector> ivec2(ivec.begin(), ivec.end()); - CHECK(ivec2.size() == 9); - CHECK(ivec2.size() == 9); - CHECK(ivec2.capacity() == 9); - CHECK(ivec2[2] == 11); - CHECK(ivec2[7] == 88); - CHECK(ivec2[8] == 11); - - ivec.erase(ivec.begin() + 1, ivec.end() - 2); - CHECK(ivec.size() == 3); - ivec.erase(ivec.end() - 1); - CHECK(ivec.size() == 2); - CHECK(ivec.capacity() == 5); - CHECK(ivec.data() == d); - - ivec2.erase(ivec2.begin() + 1, ivec2.end() - 2); - CHECK(ivec2.size() == 3); - CHECK(ivec2.capacity() == 3); - } - - CHECK(allocations == deallocations); - CHECK(allocated_bytes == deallocated_bytes); - CHECK(constructions == destructions); - - allocations = deallocations = allocated_bytes = deallocated_bytes = constructions = destructions = 0; -} - -#if !defined(__EMSCRIPTEN__) || !defined(NDEBUG) // emscripten allows exceptions with -O0 -TEST_CASE("[small_vector] out of range") -{ - using namespace chobo; - small_vector ivec; - ivec.resize(4); - CHECK(ivec.capacity() == 5); - - CHECK_THROWS_AS(ivec.insert(ivec.begin() - 1, 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.insert(ivec.end() + 1, 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.begin() - 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.end() + 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.begin() - 1, ivec.begin() + 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.begin() + 2, ivec.end() + 1), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.end() + 1, ivec.end() + 3), std::out_of_range); - CHECK(ivec.size() == 4); - CHECK_THROWS_AS(ivec.erase(ivec.end() - 1, ivec.begin() + 1), std::out_of_range); - CHECK(ivec.size() == 4); - -} -#endif - - -#endif diff --git a/include/vtkmdiy/thread.hpp b/include/vtkmdiy/thread.hpp index 8c35b2d8e..430fedc80 100644 --- a/include/vtkmdiy/thread.hpp +++ b/include/vtkmdiy/thread.hpp @@ -41,6 +41,9 @@ namespace diy #include "critical-resource.hpp" #if !defined(VTKMDIY_NO_THREADS) + +#include // for shared_ptr + template struct diy::concurrent_map { diff --git a/include/vtkmdiy/version.hpp b/include/vtkmdiy/version.hpp index 7bbe4df16..d3a1a3c6b 100644 --- a/include/vtkmdiy/version.hpp +++ b/include/vtkmdiy/version.hpp @@ -3,6 +3,6 @@ #define VTKMDIY_VERSION_MAJOR 3 #define VTKMDIY_VERSION_MINOR 5 -#define DIY_VERSION_PATCH dev1 +#define VTKMDIY_VERSION_PATCH dev1 #endif From 1e2749580997032400ee8b2330a88418c60ee332 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Wed, 22 Mar 2023 19:14:21 -0400 Subject: [PATCH 09/38] diy,mpi: Enable GPU AWARE MPI buffers This commit adds the flag VTKm_ENABLE_GPU_MPI which when enable it will use GPU AWARE MPI. - This will only work with GPUs and MPI implementation that supports GPU AWARE MPI calls. - Enabling VTKm_ENABLE_GPU_MPI without MPI/GPU support might results in errors when running VTK-m with DIY/MPI. - Only the following tests can run with this feature if enabled: - UnitTestSerializationDataSet - UnitTestSerializationArrayHandle --- CMakeLists.txt | 5 ++ vtkm/cont/CMakeLists.txt | 2 + vtkm/cont/DIYMemoryManagement.cxx | 78 +++++++++++++++++++ vtkm/cont/DIYMemoryManagement.h | 30 +++++++ vtkm/cont/RuntimeDeviceInformation.cxx | 5 ++ .../DeviceAdapterMemoryManagerCuda.cu | 5 ++ .../internal/DeviceAdapterMemoryManagerCuda.h | 2 + vtkm/cont/internal/Buffer.cxx | 41 +++++++--- .../internal/DeviceAdapterMemoryManager.cxx | 37 ++++++--- .../internal/DeviceAdapterMemoryManager.h | 39 ++++++++++ .../DeviceAdapterMemoryManagerShared.cxx | 6 ++ .../DeviceAdapterMemoryManagerShared.h | 2 + .../DeviceAdapterMemoryManagerKokkos.cxx | 26 +++++++ .../DeviceAdapterMemoryManagerKokkos.h | 6 ++ vtkm/cont/testing/TestingSerialization.h | 5 +- vtkm/internal/CMakeLists.txt | 1 + vtkm/internal/Configure.h.in | 3 + 17 files changed, 270 insertions(+), 23 deletions(-) create mode 100644 vtkm/cont/DIYMemoryManagement.cxx create mode 100644 vtkm/cont/DIYMemoryManagement.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0065590b1..b92561523 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,11 @@ vtkm_option(VTKm_SKIP_LIBRARY_VERSIONS "Skip versioning VTK-m libraries" OFF) # through ctest's command-line. Doesn't affect CI unless enabled. vtkm_option(VTKm_OVERRIDE_CTEST_TIMEOUT "Disable default ctest timeout" OFF) +# VTKm_ENABLE_GPU_MPI makes VTK-m to use DIY routines that enables GPU aware +# MPI. By default, this option is disabled. Also, this option is hidden unless +# VTKm_ENABLE_MPI=ON. +cmake_dependent_option(VTKm_ENABLE_GPU_MPI "Enable GPU AWARE MPI support" OFF "VTKm_ENABLE_MPI" OFF) + mark_as_advanced( VTKm_ENABLE_LOGGING VTKm_NO_ASSERT diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 53b5308d5..9e824ff95 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -86,6 +86,7 @@ set(headers DeviceAdapterAlgorithm.h DeviceAdapterList.h DeviceAdapterTag.h + DIYMemoryManagement.h EnvironmentTracker.h Error.h ErrorBadAllocation.h @@ -154,6 +155,7 @@ set(sources DataSetBuilderRectilinear.cxx DataSetBuilderUniform.cxx DeviceAdapterTag.cxx + DIYMemoryManagement.cxx EnvironmentTracker.cxx ErrorBadDevice.cxx ErrorBadType.cxx diff --git a/vtkm/cont/DIYMemoryManagement.cxx b/vtkm/cont/DIYMemoryManagement.cxx new file mode 100644 index 000000000..647a285fd --- /dev/null +++ b/vtkm/cont/DIYMemoryManagement.cxx @@ -0,0 +1,78 @@ +//============================================================================ +// 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 +#ifdef VTKM_ENABLE_GPU_MPI +#include +#endif + +namespace +{ + +thread_local vtkm::cont::DeviceAdapterId DIYCurrentDeviceAdaptor = + vtkm::cont::DeviceAdapterTagSerial(); + +vtkm::cont::internal::DeviceAdapterMemoryManagerBase& GetMemoryManager( + vtkm::cont::DeviceAdapterId device) +{ + return vtkm::cont::RuntimeDeviceInformation().GetMemoryManager(device); +} + +vtkmdiy::MemoryManagement GetDIYMemoryManagement(vtkm::cont::DeviceAdapterId device) +{ + return vtkmdiy::MemoryManagement( + [device](int, size_t n) { + return static_cast(GetMemoryManager(device).AllocateRawPointer(n)); + }, + [device](const char* p) { GetMemoryManager(device).DeleteRawPointer(const_cast(p)); }, + [device](char* dest, const char* src, size_t count) { + GetMemoryManager(device).CopyDeviceToDeviceRawPointer(src, dest, count); + }); +} + +} + +namespace vtkm +{ +namespace cont +{ + +vtkm::cont::DeviceAdapterId GetDIYDeviceAdapter() +{ + return DIYCurrentDeviceAdaptor; +} + +void DIYMasterExchange(vtkmdiy::Master& master, bool remote) +{ +#ifdef VTKM_ENABLE_GPU_MPI + try + { + DIYCurrentDeviceAdaptor = vtkm::cont::DeviceAdapterTagKokkos(); + master.exchange(remote, GetDIYMemoryManagement(vtkm::cont::DeviceAdapterTagKokkos())); + DIYCurrentDeviceAdaptor = vtkm::cont::DeviceAdapterTagSerial(); + } + catch (...) + { + DIYCurrentDeviceAdaptor = vtkm::cont::DeviceAdapterTagSerial(); + throw; + } +#else + DIYCurrentDeviceAdaptor = vtkm::cont::DeviceAdapterTagSerial(); + master.exchange(remote); +#endif +} + +} +} diff --git a/vtkm/cont/DIYMemoryManagement.h b/vtkm/cont/DIYMemoryManagement.h new file mode 100644 index 000000000..ad502a412 --- /dev/null +++ b/vtkm/cont/DIYMemoryManagement.h @@ -0,0 +1,30 @@ +//============================================================================ +// 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_internal_DIYMemoryManagement_h +#define vtk_m_cont_internal_DIYMemoryManagement_h + +#include +#include +#include + +namespace vtkm +{ +namespace cont +{ + +VTKM_CONT_EXPORT vtkm::cont::DeviceAdapterId GetDIYDeviceAdapter(); + +/// \brief Wraps vtkmdiy::Master::exchange by setting its appropiate vtkmdiy::MemoryManagement. +VTKM_CONT_EXPORT void DIYMasterExchange(vtkmdiy::Master& master, bool remote = false); + +} +} + +#endif diff --git a/vtkm/cont/RuntimeDeviceInformation.cxx b/vtkm/cont/RuntimeDeviceInformation.cxx index f8e95eb3b..d9d0f8996 100644 --- a/vtkm/cont/RuntimeDeviceInformation.cxx +++ b/vtkm/cont/RuntimeDeviceInformation.cxx @@ -78,6 +78,11 @@ public: { throw vtkm::cont::ErrorBadDevice("Tried to manage memory on an invalid device."); } + + VTKM_CONT virtual void DeleteRawPointer(void*) const override + { + throw vtkm::cont::ErrorBadDevice("Tried to manage memory on an invalid device."); + } }; class RuntimeDeviceConfigurationInvalid final diff --git a/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.cu b/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.cu index c972505a8..e12abc95e 100644 --- a/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.cu +++ b/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.cu @@ -240,6 +240,11 @@ void DeviceAdapterMemoryManager::CopyDeviceToD cudaMemcpyDeviceToDevice, cudaStreamPerThread)); } + +void DeviceAdapterMemoryManager::DeleteRawPointer(void* mem) const +{ + CudaDelete(mem); +}; } } } // namespace vtkm::cont::internal diff --git a/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.h b/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.h index d819a5762..af0139a1c 100644 --- a/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.h +++ b/vtkm/cont/cuda/internal/DeviceAdapterMemoryManagerCuda.h @@ -50,6 +50,8 @@ public: VTKM_CONT virtual void CopyDeviceToDevice( const vtkm::cont::internal::BufferInfo& src, const vtkm::cont::internal::BufferInfo& dest) const override; + + VTKM_CONT virtual void DeleteRawPointer(void* mem) const override; }; } } diff --git a/vtkm/cont/internal/Buffer.cxx b/vtkm/cont/internal/Buffer.cxx index 9879daf14..7320c6187 100644 --- a/vtkm/cont/internal/Buffer.cxx +++ b/vtkm/cont/internal/Buffer.cxx @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -1158,30 +1159,46 @@ void Serialization::save(BinaryBuffer& bb, const vtkm::cont::internal::Buffer& obj) { vtkm::BufferSizeType size = obj.GetNumberOfBytes(); - vtkmdiy::save(bb, size); + std::unique_ptr token; + const void* ptr = nullptr; - if (size) + if (size > 0) { - // NOTE: If size == 0, obj.ReadPointerHost will be a nullptr, and saving that via - // vtkmdiy causes test failure on osheim - vtkm::cont::Token token; - const vtkm::UInt8* data = reinterpret_cast(obj.ReadPointerHost(token)); - vtkmdiy::save(bb, data, static_cast(size)); + token.reset(new vtkm::cont::Token); + ptr = obj.ReadPointerDevice(vtkm::cont::GetDIYDeviceAdapter(), *token); } + + // We need to keep the token alive until the data is consumed by DIY, + // otherwise the pointed data could be freed before it is consumed. + // Note that we cannot simply have the unique_ptr captured by the below + // lambda since save_binary_blob 3rd argument is a std::function and + // std::function needs for every parameter to be CopyAsignable, which + // vtkm::cont::Token is not. + bb.save_binary_blob(static_cast(ptr), + static_cast(size), + [token = token.release()](const char[]) { + if (token != nullptr) + { + token->DetachFromAll(); + delete token; + } + }); } void Serialization::load(BinaryBuffer& bb, vtkm::cont::internal::Buffer& obj) { - vtkm::BufferSizeType size; - vtkmdiy::load(bb, size); - vtkm::cont::Token token; + auto blob = bb.load_binary_blob(); + vtkm::BufferSizeType size = blob.size; obj.SetNumberOfBytes(size, vtkm::CopyFlag::Off, token); + if (size) { - vtkm::UInt8* data = reinterpret_cast(obj.WritePointerHost(token)); - vtkmdiy::load(bb, data, static_cast(size)); + auto device = vtkm::cont::GetDIYDeviceAdapter(); + void* ptr = obj.WritePointerDevice(device, token); + vtkm::cont::RuntimeDeviceInformation().GetMemoryManager(device).CopyDeviceToDeviceRawPointer( + blob.pointer.get(), ptr, size); } } diff --git a/vtkm/cont/internal/DeviceAdapterMemoryManager.cxx b/vtkm/cont/internal/DeviceAdapterMemoryManager.cxx index c37056cc5..15345e3d5 100644 --- a/vtkm/cont/internal/DeviceAdapterMemoryManager.cxx +++ b/vtkm/cont/internal/DeviceAdapterMemoryManager.cxx @@ -42,7 +42,11 @@ #include #include -namespace +namespace vtkm +{ +namespace cont +{ +namespace internal { /// A deleter object that can be used with our aligned mallocs @@ -120,15 +124,6 @@ void HostReallocate(void*& memory, memory = container = newBuffer; } -} // anonymous namespace - -namespace vtkm -{ -namespace cont -{ -namespace internal -{ - VTKM_CONT void InvalidRealloc(void*&, void*&, vtkm::BufferSizeType, vtkm::BufferSizeType) { throw vtkm::cont::ErrorBadAllocation("User provided memory does not have a reallocater."); @@ -340,6 +335,28 @@ vtkm::cont::internal::BufferInfo DeviceAdapterMemoryManagerBase::ManageArray( return vtkm::cont::internal::BufferInfo( this->GetDevice(), memory, container, size, deleter, reallocater); } + +void* DeviceAdapterMemoryManagerBase::AllocateRawPointer(vtkm::BufferSizeType size) const +{ + return this->Allocate(size).TransferOwnership().Memory; +} + +void DeviceAdapterMemoryManagerBase::CopyDeviceToDeviceRawPointer(const void* src, + void* dest, + vtkm::BufferSizeType size) const +{ + this->CopyDeviceToDevice( + vtkm::cont::internal::BufferInfo( + this->GetDevice(), + const_cast(src), + const_cast(src), + size, + [](void*) {}, + vtkm::cont::internal::InvalidRealloc), + vtkm::cont::internal::BufferInfo( + this->GetDevice(), dest, dest, size, [](void*) {}, vtkm::cont::internal::InvalidRealloc)); +} + } } } // namespace vtkm::cont::internal diff --git a/vtkm/cont/internal/DeviceAdapterMemoryManager.h b/vtkm/cont/internal/DeviceAdapterMemoryManager.h index b27e537f2..146dd4b20 100644 --- a/vtkm/cont/internal/DeviceAdapterMemoryManager.h +++ b/vtkm/cont/internal/DeviceAdapterMemoryManager.h @@ -196,6 +196,37 @@ public: /// objects were created by a previous call to this object. VTKM_CONT virtual void CopyDeviceToDevice(const vtkm::cont::internal::BufferInfo& src, const vtkm::cont::internal::BufferInfo& dest) const = 0; + + + /// \brief Low-level method to allocate memory on the device. + /// + /// This method allocates an array of the given number of bytes on the device and returns + /// a void pointer to the array. The preferred method to allocate memory is to use the + /// `Allocate` method, which returns a `BufferInfo` that manages its own memory. However, + /// for cases where you are interfacing with code outside of VTK-m and need just a raw + /// pointer, this method can be used. The returned memory can be freed with + /// `DeleteRawPointer`. + VTKM_CONT virtual void* AllocateRawPointer(vtkm::BufferSizeType size) const; + + /// \brief Low-level method to copy data on the device. + /// + /// This method copies data from one raw pointer to another. It performs the same + /// function as `CopyDeviceToDevice`, except that it operates on raw pointers + /// instead of `BufferInfo` objects. This is a useful low-level mechanism to move + /// data on a device in memory locations created externally to VTK-m. + VTKM_CONT virtual void CopyDeviceToDeviceRawPointer(const void* src, + void* dest, + vtkm::BufferSizeType size) const; + + /// \brief Low-level method to delete memory on the device. + /// + /// This method takes a pointer to memory allocated on the device and frees it. + /// The preferred method to delete memory is to use the deallocation routines in + /// `BufferInfo` objects created with `Allocate`. But for cases where you only + /// have a raw pointer to the data, this method can be used to manage it. This + /// method should only be used on memory allocated with this + /// `DeviceAdaperMemoryManager`. + VTKM_CONT virtual void DeleteRawPointer(void*) const = 0; }; /// \brief The device adapter memory manager. @@ -207,6 +238,14 @@ public: template class DeviceAdapterMemoryManager; +VTKM_CONT_EXPORT VTKM_CONT void HostDeleter(void*); +VTKM_CONT_EXPORT VTKM_CONT void* HostAllocate(vtkm::BufferSizeType); +VTKM_CONT_EXPORT VTKM_CONT void HostReallocate(void*&, + void*&, + vtkm::BufferSizeType, + vtkm::BufferSizeType); + + VTKM_CONT_EXPORT VTKM_CONT void InvalidRealloc(void*&, void*&, vtkm::BufferSizeType, diff --git a/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.cxx b/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.cxx index aa3a7ed59..52e37b05c 100644 --- a/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.cxx +++ b/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.cxx @@ -83,6 +83,12 @@ void DeviceAdapterMemoryManagerShared::CopyDeviceToDevice( std::memcpy(dest.GetPointer(), src.GetPointer(), static_cast(src.GetSize())); } + +void DeviceAdapterMemoryManagerShared::DeleteRawPointer(void* mem) const +{ + vtkm::cont::internal::HostDeleter(mem); +} + } } } // namespace vtkm::cont::internal diff --git a/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.h b/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.h index c17dead0b..254a0bd7f 100644 --- a/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.h +++ b/vtkm/cont/internal/DeviceAdapterMemoryManagerShared.h @@ -50,6 +50,8 @@ public: VTKM_CONT virtual void CopyDeviceToDevice( const vtkm::cont::internal::BufferInfo& src, const vtkm::cont::internal::BufferInfo& dest) const override; + + VTKM_CONT virtual void DeleteRawPointer(void* mem) const override; }; } } diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.cxx b/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.cxx index 64885b0e9..764e58205 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.cxx +++ b/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.cxx @@ -153,6 +153,32 @@ void DeviceAdapterMemoryManager::CopyDeviceT static_cast(dest.GetPointer()), static_cast(size)); Kokkos::deep_copy(vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), destView, srcView); } + +// Low level memory management methods +void* DeviceAdapterMemoryManager::AllocateRawPointer( + vtkm::BufferSizeType size) const +{ + return vtkm::cont::kokkos::internal::Allocate(size); +} + +void DeviceAdapterMemoryManager::CopyDeviceToDeviceRawPointer( + const void* src, + void* dest, + vtkm::BufferSizeType size) const +{ + Kokkos::View> destView(static_cast(dest), + size); + Kokkos::View> srcView( + static_cast(src), size); + Kokkos::deep_copy(vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), destView, srcView); +} + +void DeviceAdapterMemoryManager::DeleteRawPointer( + void* mem) const +{ + vtkm::cont::kokkos::internal::Free(mem); +} + } } } // vtkm::cont::internal diff --git a/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.h b/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.h index 5a8ff0ce8..a1002d626 100644 --- a/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.h +++ b/vtkm/cont/kokkos/internal/DeviceAdapterMemoryManagerKokkos.h @@ -50,6 +50,12 @@ public: VTKM_CONT virtual void CopyDeviceToDevice( const vtkm::cont::internal::BufferInfo& src, const vtkm::cont::internal::BufferInfo& dest) const override; + + VTKM_CONT void* AllocateRawPointer(vtkm::BufferSizeType size) const override; + VTKM_CONT void CopyDeviceToDeviceRawPointer(const void* src, + void* dest, + vtkm::BufferSizeType size) const override; + VTKM_CONT void DeleteRawPointer(void* mem) const override; }; } } diff --git a/vtkm/cont/testing/TestingSerialization.h b/vtkm/cont/testing/TestingSerialization.h index 6275f84b1..1f8455b85 100644 --- a/vtkm/cont/testing/TestingSerialization.h +++ b/vtkm/cont/testing/TestingSerialization.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -189,7 +190,9 @@ void TestSerialization(const T& obj, const TestEqualFunctor& test) master.foreach ([](Block* b, const vtkmdiy::Master::ProxyWithLink& cp) { cp.enqueue(cp.link()->target(0), b->send); }); - master.exchange(); + + vtkm::cont::DIYMasterExchange(master); + master.foreach ([](Block* b, const vtkmdiy::Master::ProxyWithLink& cp) { cp.dequeue(cp.link()->target(1).gid, b->received); }); diff --git a/vtkm/internal/CMakeLists.txt b/vtkm/internal/CMakeLists.txt index 8e6989c3a..4b4463607 100755 --- a/vtkm/internal/CMakeLists.txt +++ b/vtkm/internal/CMakeLists.txt @@ -26,6 +26,7 @@ set(VTKM_ENABLE_OPENMP ${VTKm_ENABLE_OPENMP}) set(VTKM_ENABLE_TBB ${VTKm_ENABLE_TBB}) set(VTKM_ENABLE_MPI ${VTKm_ENABLE_MPI}) +set(VTKM_ENABLE_GPU_MPI ${VTKm_ENABLE_GPU_MPI}) if(VTKM_ENABLE_CUDA) string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" VTKM_CUDA_VERSION_MAJOR ${CMAKE_CUDA_COMPILER_VERSION}) diff --git a/vtkm/internal/Configure.h.in b/vtkm/internal/Configure.h.in index f2caf2a64..7a4b15c25 100644 --- a/vtkm/internal/Configure.h.in +++ b/vtkm/internal/Configure.h.in @@ -308,6 +308,9 @@ //Mark if we are building with MPI enabled. #cmakedefine VTKM_ENABLE_MPI +//Mark if we are building with GPU AWARE MPI enabled. +#cmakedefine VTKM_ENABLE_GPU_MPI + //Mark what version of the CUDA compiler we have. This is needed to correctly //choose consistent implementation ( so we don't violate ODR ) when we compile //with CUDA 7.5 From c39ff5f86e241e4608315377caf6aace1402493d Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Tue, 30 May 2023 13:01:02 -0600 Subject: [PATCH 10/38] add include CanvasRayTracer.h --- benchmarking/BenchmarkRayTracing.cxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/benchmarking/BenchmarkRayTracing.cxx b/benchmarking/BenchmarkRayTracing.cxx index f6c7ae261..799e52bfc 100644 --- a/benchmarking/BenchmarkRayTracing.cxx +++ b/benchmarking/BenchmarkRayTracing.cxx @@ -13,20 +13,17 @@ #include #include -#include #include #include #include #include +#include #include #include -#include #include -#include - #include #include #include From 8a44ea4a918b20d74a14447fe8444de399f26668 Mon Sep 17 00:00:00 2001 From: roxana bujack Date: Thu, 1 Jun 2023 15:41:39 +0200 Subject: [PATCH 11/38] adapt pixel wrongnes ratio --- .../filter/image_processing/testing/RenderTestComputeMoments.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx b/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx index 5d6fb2305..9514069c2 100644 --- a/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx +++ b/vtkm/filter/image_processing/testing/RenderTestComputeMoments.cxx @@ -29,6 +29,7 @@ void TestComputeMoments() vtkm::cont::DataSet result = filter.Execute(data); vtkm::rendering::testing::RenderTestOptions testOptions; + testOptions.AllowedPixelErrorRatio = 0.001f; testOptions.ColorTable = vtkm::cont::ColorTable("inferno"); testOptions.EnableAnnotations = false; vtkm::rendering::testing::RenderTest(result, "index", "filter/moments.png", testOptions); From 6508d47cbc13e6ad9f3bdc1ac211a610b9b067f6 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 1 Jun 2023 10:53:35 -0400 Subject: [PATCH 12/38] Remove 3DPara --- vtkm/rendering/Camera.h | 1 - 1 file changed, 1 deletion(-) diff --git a/vtkm/rendering/Camera.h b/vtkm/rendering/Camera.h index b9ecf50fc..2e8113db0 100644 --- a/vtkm/rendering/Camera.h +++ b/vtkm/rendering/Camera.h @@ -96,7 +96,6 @@ public: { TwoD, ThreeD, - Three3DPara, }; VTKM_CONT From 6b0d2e369c59f800446f9b7bad5b54b6e546d989 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 1 Jun 2023 11:28:49 -0600 Subject: [PATCH 13/38] use unique_ptr for PIMPL Actor --- examples/demo/Demo.cxx | 4 ++-- vtkm/rendering/Actor.cxx | 37 +++++++++++++++++++++---------------- vtkm/rendering/Actor.h | 12 +++++++++--- vtkm/rendering/Scene.cxx | 4 ++-- vtkm/rendering/Scene.h | 2 +- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/examples/demo/Demo.cxx b/examples/demo/Demo.cxx index 08f32717d..8f289fed1 100644 --- a/examples/demo/Demo.cxx +++ b/examples/demo/Demo.cxx @@ -55,7 +55,7 @@ int main(int argc, char* argv[]) tangleData.GetField(fieldName), colorTable); vtkm::rendering::Scene scene; - scene.AddActor(actor); + scene.AddActor(std::move(actor)); // 2048x2048 pixels in the canvas: CanvasRayTracer canvas(2048, 2048); // Create a view and use it to render the input data using OS Mesa @@ -78,7 +78,7 @@ int main(int argc, char* argv[]) // from, so we want the scalar range to match that of the previous image. isoActor.SetScalarRange(actor.GetScalarRange()); vtkm::rendering::Scene isoScene; - isoScene.AddActor(isoActor); + isoScene.AddActor(std::move(isoActor)); // Wireframe surface: vtkm::rendering::View3D isoView(isoScene, MapperWireframer(), canvas, camera, bg); diff --git a/vtkm/rendering/Actor.cxx b/vtkm/rendering/Actor.cxx index 349cf5244..240cfaf39 100644 --- a/vtkm/rendering/Actor.cxx +++ b/vtkm/rendering/Actor.cxx @@ -10,10 +10,11 @@ #include -#include #include #include +#include + namespace vtkm { namespace rendering @@ -30,25 +31,25 @@ struct Actor::InternalsType vtkm::Bounds SpatialBounds; VTKM_CONT - InternalsType(const vtkm::cont::UnknownCellSet& cells, - const vtkm::cont::CoordinateSystem& coordinates, - const vtkm::cont::Field& scalarField, + InternalsType(vtkm::cont::UnknownCellSet cells, + vtkm::cont::CoordinateSystem coordinates, + vtkm::cont::Field scalarField, const vtkm::rendering::Color& color) - : Cells(cells) - , Coordinates(coordinates) - , ScalarField(scalarField) + : Cells(std::move(cells)) + , Coordinates(std::move(coordinates)) + , ScalarField(std::move(scalarField)) , ColorTable(vtkm::Range{ 0, 1 }, color.Components, color.Components) { } VTKM_CONT - InternalsType(const vtkm::cont::UnknownCellSet& cells, - const vtkm::cont::CoordinateSystem& coordinates, - const vtkm::cont::Field& scalarField, + InternalsType(vtkm::cont::UnknownCellSet cells, + vtkm::cont::CoordinateSystem coordinates, + vtkm::cont::Field scalarField, const vtkm::cont::ColorTable& colorTable = vtkm::cont::ColorTable::Preset::Default) - : Cells(cells) - , Coordinates(coordinates) - , ScalarField(scalarField) + : Cells(std::move(cells)) + , Coordinates(std::move(coordinates)) + , ScalarField(std::move(scalarField)) , ColorTable(colorTable) { } @@ -57,7 +58,7 @@ struct Actor::InternalsType Actor::Actor(const vtkm::cont::UnknownCellSet& cells, const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField) - : Internals(new InternalsType(cells, coordinates, scalarField)) + : Internals(std::make_unique(cells, coordinates, scalarField)) { this->Init(coordinates, scalarField); } @@ -66,7 +67,7 @@ Actor::Actor(const vtkm::cont::UnknownCellSet& cells, const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField, const vtkm::rendering::Color& color) - : Internals(new InternalsType(cells, coordinates, scalarField, color)) + : Internals(std::make_unique(cells, coordinates, scalarField, color)) { this->Init(coordinates, scalarField); } @@ -75,11 +76,15 @@ Actor::Actor(const vtkm::cont::UnknownCellSet& cells, const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField, const vtkm::cont::ColorTable& colorTable) - : Internals(new InternalsType(cells, coordinates, scalarField, colorTable)) + : Internals(std::make_unique(cells, coordinates, scalarField, colorTable)) { this->Init(coordinates, scalarField); } +Actor::~Actor() = default; +Actor::Actor(vtkm::rendering::Actor&&) noexcept = default; +Actor& Actor::operator=(Actor&&) noexcept = default; + void Actor::Init(const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField) { diff --git a/vtkm/rendering/Actor.h b/vtkm/rendering/Actor.h index 1c7f03c22..9716d9b79 100644 --- a/vtkm/rendering/Actor.h +++ b/vtkm/rendering/Actor.h @@ -40,6 +40,14 @@ public: const vtkm::cont::Field& scalarField, const vtkm::rendering::Color& color); + // Disable copying due to unique_ptr; + Actor(const Actor&) = delete; + Actor& operator=(const Actor&) = delete; + + Actor(Actor&&) noexcept; + Actor& operator=(Actor&&) noexcept; + ~Actor(); + void Render(vtkm::rendering::Mapper& mapper, vtkm::rendering::Canvas& canvas, const vtkm::rendering::Camera& camera) const; @@ -60,9 +68,7 @@ public: private: struct InternalsType; - std::shared_ptr Internals; - - struct RangeFunctor; + std::unique_ptr Internals; void Init(const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField); }; diff --git a/vtkm/rendering/Scene.cxx b/vtkm/rendering/Scene.cxx index 676844fe9..3e5bd0f26 100644 --- a/vtkm/rendering/Scene.cxx +++ b/vtkm/rendering/Scene.cxx @@ -27,9 +27,9 @@ Scene::Scene() { } -void Scene::AddActor(const vtkm::rendering::Actor& actor) +void Scene::AddActor(vtkm::rendering::Actor&& actor) { - this->Internals->Actors.push_back(actor); + this->Internals->Actors.push_back(std::move(actor)); } const vtkm::rendering::Actor& Scene::GetActor(vtkm::IdComponent index) const diff --git a/vtkm/rendering/Scene.h b/vtkm/rendering/Scene.h index 68a718e06..4a9f0f42c 100644 --- a/vtkm/rendering/Scene.h +++ b/vtkm/rendering/Scene.h @@ -29,7 +29,7 @@ class VTKM_RENDERING_EXPORT Scene public: Scene(); - void AddActor(const vtkm::rendering::Actor& actor); + void AddActor(vtkm::rendering::Actor&& actor); const vtkm::rendering::Actor& GetActor(vtkm::IdComponent index) const; From b2880566d50e415d80e39b699817a605a1ece364 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 1 Jun 2023 11:46:06 -0600 Subject: [PATCH 14/38] move Actor --- examples/ising/Ising.cxx | 2 +- tutorial/rendering.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ising/Ising.cxx b/examples/ising/Ising.cxx index 48f748ff5..e2942c1e7 100644 --- a/examples/ising/Ising.cxx +++ b/examples/ising/Ising.cxx @@ -104,7 +104,7 @@ int main(int argc, char** argv) dataSet.GetCoordinateSystem(), dataSet.GetCellField("spins"), vtkm::cont::ColorTable("Cool To Warm")); - scene.AddActor(actor); + scene.AddActor(std::move(actor)); vtkm::rendering::CanvasRayTracer canvas(1024, 1024); vtkm::rendering::MapperRayTracer mapper; mapper.SetShadingOn(false); diff --git a/tutorial/rendering.cxx b/tutorial/rendering.cxx index ff7e6d007..8baa0cbcd 100644 --- a/tutorial/rendering.cxx +++ b/tutorial/rendering.cxx @@ -35,7 +35,7 @@ int main(int argc, char** argv) //Creating Scene and adding Actor vtkm::rendering::Scene scene; - scene.AddActor(actor); + scene.AddActor(std::move(actor)); //Creating and initializing the View using the Canvas, Ray Tracer Mappers, and Scene vtkm::rendering::MapperRayTracer mapper; From 09c78eec43092d231f42c27caf1143bf1e074fa8 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 1 Jun 2023 14:54:27 -0600 Subject: [PATCH 15/38] use unique_ptr for PIMPL ConnectivityProxy --- vtkm/rendering/ConnectivityProxy.cxx | 15 ++++++++++----- vtkm/rendering/ConnectivityProxy.h | 17 ++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/vtkm/rendering/ConnectivityProxy.cxx b/vtkm/rendering/ConnectivityProxy.cxx index 751b3ceab..990875248 100644 --- a/vtkm/rendering/ConnectivityProxy.cxx +++ b/vtkm/rendering/ConnectivityProxy.cxx @@ -15,6 +15,8 @@ #include #include +#include + namespace vtkm { @@ -52,8 +54,6 @@ public: } } - ~InternalsType() {} - VTKM_CONT void SetUnitScalar(vtkm::Float32 unitScalar) { Tracer.SetUnitScalar(unitScalar); } @@ -241,7 +241,7 @@ public: VTKM_CONT ConnectivityProxy::ConnectivityProxy(const vtkm::cont::DataSet& dataSet, const std::string& fieldName) - : Internals(new InternalsType(dataSet, fieldName)) + : Internals(std::make_unique(dataSet, fieldName)) { } @@ -256,11 +256,16 @@ ConnectivityProxy::ConnectivityProxy(const vtkm::cont::UnknownCellSet& cellset, dataset.AddCoordinateSystem(coords); dataset.AddField(scalarField); - Internals = std::shared_ptr(new InternalsType(dataset, scalarField.GetName())); + Internals = std::make_unique(dataset, scalarField.GetName()); } VTKM_CONT -ConnectivityProxy::~ConnectivityProxy() {} +ConnectivityProxy::ConnectivityProxy(ConnectivityProxy&&) noexcept = default; +VTKM_CONT +ConnectivityProxy& ConnectivityProxy::operator=(vtkm::rendering::ConnectivityProxy&&) noexcept = + default; +VTKM_CONT +ConnectivityProxy::~ConnectivityProxy() = default; VTKM_CONT void ConnectivityProxy::SetSampleDistance(const vtkm::Float32& distance) diff --git a/vtkm/rendering/ConnectivityProxy.h b/vtkm/rendering/ConnectivityProxy.h index 6212f0384..7054bef70 100644 --- a/vtkm/rendering/ConnectivityProxy.h +++ b/vtkm/rendering/ConnectivityProxy.h @@ -34,9 +34,15 @@ public: ConnectivityProxy(const vtkm::cont::UnknownCellSet& cellset, const vtkm::cont::CoordinateSystem& coords, const vtkm::cont::Field& scalarField); - // Do not allow the default constructor - ConnectivityProxy() = delete; + + ConnectivityProxy(const ConnectivityProxy&) = delete; + ConnectivityProxy& operator=(const ConnectivityProxy&) = delete; + + ConnectivityProxy(ConnectivityProxy&&) noexcept; + ConnectivityProxy& operator=(ConnectivityProxy&&) noexcept; + ~ConnectivityProxy(); + enum struct RenderMode { Volume, @@ -45,10 +51,8 @@ public: void SetRenderMode(RenderMode mode); void SetSampleDistance(const vtkm::Float32&); - void SetCanvas(vtkm::rendering::Canvas* canvas); void SetScalarField(const std::string& fieldName); void SetEmissionField(const std::string& fieldName); - void SetCamera(const vtkm::rendering::Camera& camera); void SetScalarRange(const vtkm::Range& range); void SetColorMap(vtkm::cont::ArrayHandle& colormap); void SetCompositeBackground(bool on); @@ -69,9 +73,8 @@ public: protected: struct InternalsType; - struct BoundsFunctor; - std::shared_ptr Internals; + std::unique_ptr Internals; }; } } //namespace vtkm::rendering -#endif //vtk_m_rendering_SceneRendererVolume_h +#endif //vtk_m_rendering_ConnectivityProxy_h From 04b6d96aab1c1356085198148467173d79c945af Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Fri, 2 Jun 2023 10:32:44 -0600 Subject: [PATCH 16/38] enable copying for Actor and ConnectivityProxy --- examples/demo/Demo.cxx | 2 +- examples/ising/Ising.cxx | 2 +- vtkm/rendering/Actor.cxx | 29 +++++++++++++++++++++++++++- vtkm/rendering/Actor.h | 5 ++--- vtkm/rendering/ConnectivityProxy.cxx | 29 ++++++++++++++++++++++++++++ vtkm/rendering/ConnectivityProxy.h | 4 ++-- 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/examples/demo/Demo.cxx b/examples/demo/Demo.cxx index 8f289fed1..35e099016 100644 --- a/examples/demo/Demo.cxx +++ b/examples/demo/Demo.cxx @@ -55,7 +55,7 @@ int main(int argc, char* argv[]) tangleData.GetField(fieldName), colorTable); vtkm::rendering::Scene scene; - scene.AddActor(std::move(actor)); + scene.AddActor(actor); // 2048x2048 pixels in the canvas: CanvasRayTracer canvas(2048, 2048); // Create a view and use it to render the input data using OS Mesa diff --git a/examples/ising/Ising.cxx b/examples/ising/Ising.cxx index e2942c1e7..48f748ff5 100644 --- a/examples/ising/Ising.cxx +++ b/examples/ising/Ising.cxx @@ -104,7 +104,7 @@ int main(int argc, char** argv) dataSet.GetCoordinateSystem(), dataSet.GetCellField("spins"), vtkm::cont::ColorTable("Cool To Warm")); - scene.AddActor(std::move(actor)); + scene.AddActor(actor); vtkm::rendering::CanvasRayTracer canvas(1024, 1024); vtkm::rendering::MapperRayTracer mapper; mapper.SetShadingOn(false); diff --git a/vtkm/rendering/Actor.cxx b/vtkm/rendering/Actor.cxx index 240cfaf39..e9be71c9e 100644 --- a/vtkm/rendering/Actor.cxx +++ b/vtkm/rendering/Actor.cxx @@ -81,9 +81,36 @@ Actor::Actor(const vtkm::cont::UnknownCellSet& cells, this->Init(coordinates, scalarField); } -Actor::~Actor() = default; +Actor::Actor(const Actor& rhs) + : Internals(nullptr) +{ + // rhs might have been moved, its Internal would be nullptr + if (rhs.Internals) + Internals = std::make_unique(*rhs.Internals); +} + +Actor& Actor::operator=(const Actor& rhs) +{ + // both *this and rhs might have been moved. + if (!rhs.Internals) + { + Internals.reset(); + } + else if (!Internals) + { + Internals = std::make_unique(*rhs.Internals); + } + else + { + *Internals = *rhs.Internals; + } + + return *this; +} + Actor::Actor(vtkm::rendering::Actor&&) noexcept = default; Actor& Actor::operator=(Actor&&) noexcept = default; +Actor::~Actor() = default; void Actor::Init(const vtkm::cont::CoordinateSystem& coordinates, const vtkm::cont::Field& scalarField) diff --git a/vtkm/rendering/Actor.h b/vtkm/rendering/Actor.h index 9716d9b79..820de6bf6 100644 --- a/vtkm/rendering/Actor.h +++ b/vtkm/rendering/Actor.h @@ -40,9 +40,8 @@ public: const vtkm::cont::Field& scalarField, const vtkm::rendering::Color& color); - // Disable copying due to unique_ptr; - Actor(const Actor&) = delete; - Actor& operator=(const Actor&) = delete; + Actor(const Actor&); + Actor& operator=(const Actor&); Actor(Actor&&) noexcept; Actor& operator=(Actor&&) noexcept; diff --git a/vtkm/rendering/ConnectivityProxy.cxx b/vtkm/rendering/ConnectivityProxy.cxx index 990875248..6e0f8dcbc 100644 --- a/vtkm/rendering/ConnectivityProxy.cxx +++ b/vtkm/rendering/ConnectivityProxy.cxx @@ -259,6 +259,35 @@ ConnectivityProxy::ConnectivityProxy(const vtkm::cont::UnknownCellSet& cellset, Internals = std::make_unique(dataset, scalarField.GetName()); } +ConnectivityProxy::ConnectivityProxy(const ConnectivityProxy& rhs) + : Internals(nullptr) +{ + // rhs might have been moved, its Internal would be nullptr + if (rhs.Internals) + { + Internals = std::make_unique(*rhs.Internals); + } +} + +ConnectivityProxy& ConnectivityProxy::operator=(const ConnectivityProxy& rhs) +{ + // both *this and rhs might have been moved. + if (!rhs.Internals) + { + Internals.reset(); + } + else if (!Internals) + { + Internals = std::make_unique(*rhs.Internals); + } + else + { + *Internals = *rhs.Internals; + } + + return *this; +} + VTKM_CONT ConnectivityProxy::ConnectivityProxy(ConnectivityProxy&&) noexcept = default; VTKM_CONT diff --git a/vtkm/rendering/ConnectivityProxy.h b/vtkm/rendering/ConnectivityProxy.h index 7054bef70..f5f2916a0 100644 --- a/vtkm/rendering/ConnectivityProxy.h +++ b/vtkm/rendering/ConnectivityProxy.h @@ -35,8 +35,8 @@ public: const vtkm::cont::CoordinateSystem& coords, const vtkm::cont::Field& scalarField); - ConnectivityProxy(const ConnectivityProxy&) = delete; - ConnectivityProxy& operator=(const ConnectivityProxy&) = delete; + ConnectivityProxy(const ConnectivityProxy&); + ConnectivityProxy& operator=(const ConnectivityProxy&); ConnectivityProxy(ConnectivityProxy&&) noexcept; ConnectivityProxy& operator=(ConnectivityProxy&&) noexcept; From 62eb0e3f3da7c99436670ab26830f09c3bf4ac93 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Fri, 2 Jun 2023 10:36:39 -0600 Subject: [PATCH 17/38] copying Actor into Scene --- vtkm/rendering/Scene.cxx | 10 ++++------ vtkm/rendering/Scene.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/vtkm/rendering/Scene.cxx b/vtkm/rendering/Scene.cxx index 3e5bd0f26..13db00ff6 100644 --- a/vtkm/rendering/Scene.cxx +++ b/vtkm/rendering/Scene.cxx @@ -27,7 +27,7 @@ Scene::Scene() { } -void Scene::AddActor(vtkm::rendering::Actor&& actor) +void Scene::AddActor(vtkm::rendering::Actor actor) { this->Internals->Actors.push_back(std::move(actor)); } @@ -46,9 +46,8 @@ void Scene::Render(vtkm::rendering::Mapper& mapper, vtkm::rendering::Canvas& canvas, const vtkm::rendering::Camera& camera) const { - for (vtkm::IdComponent actorIndex = 0; actorIndex < this->GetNumberOfActors(); actorIndex++) + for (const auto& actor : this->Internals->Actors) { - const vtkm::rendering::Actor& actor = this->GetActor(actorIndex); actor.Render(mapper, canvas, camera); } } @@ -56,10 +55,9 @@ void Scene::Render(vtkm::rendering::Mapper& mapper, vtkm::Bounds Scene::GetSpatialBounds() const { vtkm::Bounds bounds; - for (vtkm::IdComponent actorIndex = 0; actorIndex < this->GetNumberOfActors(); actorIndex++) + for (const auto& actor : this->Internals->Actors) { - // accumulate all Actors' spatial bounds into the scene spatial bounds - bounds.Include(this->GetActor(actorIndex).GetSpatialBounds()); + bounds.Include(actor.GetSpatialBounds()); } return bounds; diff --git a/vtkm/rendering/Scene.h b/vtkm/rendering/Scene.h index 4a9f0f42c..00fdcf148 100644 --- a/vtkm/rendering/Scene.h +++ b/vtkm/rendering/Scene.h @@ -29,7 +29,7 @@ class VTKM_RENDERING_EXPORT Scene public: Scene(); - void AddActor(vtkm::rendering::Actor&& actor); + void AddActor(vtkm::rendering::Actor actor); const vtkm::rendering::Actor& GetActor(vtkm::IdComponent index) const; From 29c96a24fad156e93e9517c1ca73650cf7df8392 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 29 May 2023 19:20:05 -0400 Subject: [PATCH 18/38] Rename structured connectivity index conversion methods The structured connectivity classes are templated on two tags to determine what 2 incident topological elements are being accessed. Back in the day, these were called the "from" elements and "to" elements, as taken from VTK filter names like `PointDataToCellData`. However, these names were found to be very confusion, and after much debate they have been renamed to the visit element type and the incident element type. Meaning that a worklet is "visiting" elements of a particular type (such as visiting each cell) and can access "incident" elements of a particular type (such as the points incident on the cell). I found a few methods converting flat and logical indices using the old, confusing from/to convention. This changes them to the new convention. --- .../testing/UnitTestDataSetRectilinear.cxx | 4 +-- vtkm/cont/testing/UnitTestDataSetUniform.cxx | 4 +-- vtkm/exec/ConnectivityStructured.h | 35 ++++++++++++++++--- .../exec/arg/ThreadIndicesPointNeighborhood.h | 2 +- vtkm/exec/arg/ThreadIndicesTopologyMap.h | 6 ++-- .../ConnectivityStructuredInternals.h | 32 ++++++++--------- .../raytracing/MeshConnectivityBuilder.cxx | 2 +- .../raytracing/VolumeRendererStructured.cxx | 6 ++-- 8 files changed, 59 insertions(+), 32 deletions(-) diff --git a/vtkm/cont/testing/UnitTestDataSetRectilinear.cxx b/vtkm/cont/testing/UnitTestDataSetRectilinear.cxx index f1aa27f25..a953e57f6 100644 --- a/vtkm/cont/testing/UnitTestDataSetRectilinear.cxx +++ b/vtkm/cont/testing/UnitTestDataSetRectilinear.cxx @@ -92,7 +92,7 @@ static void TwoDimRectilinearTest() vtkm::Id cells[2][4] = { { 0, 1, 4, 3 }, { 1, 2, 5, 4 } }; for (vtkm::Id cellIndex = 0; cellIndex < 2; cellIndex++) { - vtkm::Id4 pointIds = pointToCell.GetIndices(pointToCell.FlatToLogicalToIndex(cellIndex)); + vtkm::Id4 pointIds = pointToCell.GetIndices(pointToCell.FlatToLogicalVisitIndex(cellIndex)); for (vtkm::IdComponent localPointIndex = 0; localPointIndex < 4; localPointIndex++) { VTKM_TEST_ASSERT(pointIds[localPointIndex] == cells[cellIndex][localPointIndex], @@ -106,7 +106,7 @@ static void TwoDimRectilinearTest() for (vtkm::Id pointIndex = 0; pointIndex < 6; pointIndex++) { vtkm::VecVariable retrievedCellIds = - cellToPoint.GetIndices(cellToPoint.FlatToLogicalToIndex(pointIndex)); + cellToPoint.GetIndices(cellToPoint.FlatToLogicalVisitIndex(pointIndex)); VTKM_TEST_ASSERT(retrievedCellIds.GetNumberOfComponents() <= 4, "Got wrong number of cell ids."); for (vtkm::IdComponent cellIndex = 0; cellIndex < retrievedCellIds.GetNumberOfComponents(); diff --git a/vtkm/cont/testing/UnitTestDataSetUniform.cxx b/vtkm/cont/testing/UnitTestDataSetUniform.cxx index ff400c015..3f0c57929 100644 --- a/vtkm/cont/testing/UnitTestDataSetUniform.cxx +++ b/vtkm/cont/testing/UnitTestDataSetUniform.cxx @@ -94,7 +94,7 @@ static void TwoDimUniformTest() vtkm::Id cells[2][4] = { { 0, 1, 4, 3 }, { 1, 2, 5, 4 } }; for (vtkm::Id cellIndex = 0; cellIndex < 2; cellIndex++) { - vtkm::Id4 pointIds = pointToCell.GetIndices(pointToCell.FlatToLogicalToIndex(cellIndex)); + vtkm::Id4 pointIds = pointToCell.GetIndices(pointToCell.FlatToLogicalVisitIndex(cellIndex)); for (vtkm::IdComponent localPointIndex = 0; localPointIndex < 4; localPointIndex++) { VTKM_TEST_ASSERT(pointIds[localPointIndex] == cells[cellIndex][localPointIndex], @@ -108,7 +108,7 @@ static void TwoDimUniformTest() for (vtkm::Id pointIndex = 0; pointIndex < 6; pointIndex++) { vtkm::VecVariable retrievedCellIds = - cellToPoint.GetIndices(cellToPoint.FlatToLogicalToIndex(pointIndex)); + cellToPoint.GetIndices(cellToPoint.FlatToLogicalVisitIndex(pointIndex)); VTKM_TEST_ASSERT(retrievedCellIds.GetNumberOfComponents() <= 4, "Got wrong number of cell ids."); for (vtkm::IdComponent cellIndex = 0; cellIndex < retrievedCellIds.GetNumberOfComponents(); diff --git a/vtkm/exec/ConnectivityStructured.h b/vtkm/exec/ConnectivityStructured.h index 0f14923c3..fd3fce942 100644 --- a/vtkm/exec/ConnectivityStructured.h +++ b/vtkm/exec/ConnectivityStructured.h @@ -11,6 +11,7 @@ #ifndef vtk_m_exec_ConnectivityStructured_h #define vtk_m_exec_ConnectivityStructured_h +#include #include #include #include @@ -77,28 +78,54 @@ public: return Helper::GetIndices(this->Internals, index); } + VTKM_EXEC_CONT SchedulingRangeType FlatToLogicalVisitIndex(vtkm::Id flatVisitIndex) const + { + return Helper::FlatToLogicalVisitIndex(this->Internals, flatVisitIndex); + } + + VTKM_EXEC_CONT SchedulingRangeType FlatToLogicalIncidentIndex(vtkm::Id flatIncidentIndex) const + { + return Helper::FlatToLogicalIncidentIndex(this->Internals, flatIncidentIndex); + } + + VTKM_EXEC_CONT vtkm::Id LogicalToFlatVisitIndex( + const SchedulingRangeType& logicalVisitIndex) const + { + return Helper::LogicalToFlatVisitIndex(this->Internals, logicalVisitIndex); + } + + VTKM_EXEC_CONT vtkm::Id LogicalToFlatIncidentIndex( + const SchedulingRangeType& logicalIncidentIndex) const + { + return Helper::LogicalToFlatIncidentIndex(this->Internals, logicalIncidentIndex); + } + VTKM_EXEC_CONT + VTKM_DEPRECATED(2.1, "Use FlatToLogicalIncidentIndex.") SchedulingRangeType FlatToLogicalFromIndex(vtkm::Id flatFromIndex) const { - return Helper::FlatToLogicalFromIndex(this->Internals, flatFromIndex); + return this->FlatToLogicalIncidentIndex(flatFromIndex); } VTKM_EXEC_CONT + VTKM_DEPRECATED(2.1, "Use LogicalToFlatIncidentIndex.") vtkm::Id LogicalToFlatFromIndex(const SchedulingRangeType& logicalFromIndex) const { - return Helper::LogicalToFlatFromIndex(this->Internals, logicalFromIndex); + return this->LogicalToFlatIncidentIndex(logicalFromIndex); } VTKM_EXEC_CONT + VTKM_DEPRECATED(2.1, "Use FlatToLogicalVisitIndex.") SchedulingRangeType FlatToLogicalToIndex(vtkm::Id flatToIndex) const { - return Helper::FlatToLogicalToIndex(this->Internals, flatToIndex); + return this->FlatToLogicalVisitIndex(flatToIndex); } VTKM_EXEC_CONT + VTKM_DEPRECATED(2.1, "Use LogicalToFlatVisitIndex.") vtkm::Id LogicalToFlatToIndex(const SchedulingRangeType& logicalToIndex) const { - return Helper::LogicalToFlatToIndex(this->Internals, logicalToIndex); + return this->LogicalToFlatVisitIndex(logicalToIndex); } VTKM_EXEC_CONT diff --git a/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h b/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h index 00318e25a..4bcf7f915 100644 --- a/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h +++ b/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h @@ -72,7 +72,7 @@ public: inputIndex, visitIndex, outputIndex, - vtkm::exec::BoundaryState{ detail::To3D(connectivity.FlatToLogicalToIndex(inputIndex)), + vtkm::exec::BoundaryState{ detail::To3D(connectivity.FlatToLogicalVisitIndex(inputIndex)), detail::To3D(connectivity.GetPointDimensions()) }) { } diff --git a/vtkm/exec/arg/ThreadIndicesTopologyMap.h b/vtkm/exec/arg/ThreadIndicesTopologyMap.h index 95f2c9165..970afa0fa 100644 --- a/vtkm/exec/arg/ThreadIndicesTopologyMap.h +++ b/vtkm/exec/arg/ThreadIndicesTopologyMap.h @@ -181,7 +181,7 @@ public: this->InputIndex = inputIndex; this->VisitIndex = visitIndex; this->OutputIndex = outputIndex; - this->LogicalIndex = connectivity.FlatToLogicalToIndex(this->InputIndex); + this->LogicalIndex = connectivity.FlatToLogicalVisitIndex(this->InputIndex); this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex); this->CellShape = connectivity.GetCellShape(this->InputIndex); } @@ -338,7 +338,7 @@ public: const ConnectivityType& connectivity) { this->ThreadIndex = threadIndex; - this->LogicalIndex = connectivity.FlatToLogicalToIndex(inputIndex); + this->LogicalIndex = connectivity.FlatToLogicalVisitIndex(inputIndex); this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex); this->CellShape = connectivity.GetCellShape(inputIndex); } @@ -503,7 +503,7 @@ public: this->OutputIndex = outputIndex; const vtkm::Id permutedIndex = permutation.Portal.Get(this->InputIndex); - this->LogicalIndex = permutation.Connectivity.FlatToLogicalToIndex(permutedIndex); + this->LogicalIndex = permutation.Connectivity.FlatToLogicalVisitIndex(permutedIndex); this->IndicesIncident = permutation.Connectivity.GetIndices(this->LogicalIndex); this->CellShape = permutation.Connectivity.GetCellShape(permutedIndex); } diff --git a/vtkm/internal/ConnectivityStructuredInternals.h b/vtkm/internal/ConnectivityStructuredInternals.h index 7e2e0717a..448faf6d6 100644 --- a/vtkm/internal/ConnectivityStructuredInternals.h +++ b/vtkm/internal/ConnectivityStructuredInternals.h @@ -607,29 +607,29 @@ struct ConnectivityStructuredIndexHelper cellIndices = Connectivity.GetIndices(cellId); // Look up the offset into the face list for each cell type diff --git a/vtkm/rendering/raytracing/VolumeRendererStructured.cxx b/vtkm/rendering/raytracing/VolumeRendererStructured.cxx index 86d084d2c..9fff4ef35 100644 --- a/vtkm/rendering/raytracing/VolumeRendererStructured.cxx +++ b/vtkm/rendering/raytracing/VolumeRendererStructured.cxx @@ -61,7 +61,7 @@ public: vtkm::Id cellId{}; auto self = static_cast(this); self->Locator.FindCell(point, cellId, parametric); - cell = self->Conn.FlatToLogicalToIndex(cellId); + cell = self->Conn.FlatToLogicalVisitIndex(cellId); self->ComputeInvSpacing(cell, point, invSpacing, parametric); } @@ -74,7 +74,7 @@ public: VTKM_EXEC inline vtkm::Id GetCellIndex(const vtkm::Id3& cell) const { - return static_cast(this)->Conn.LogicalToFlatToIndex(cell); + return static_cast(this)->Conn.LogicalToFlatVisitIndex(cell); } VTKM_EXEC @@ -88,7 +88,7 @@ public: inline void GetMinPoint(const vtkm::Id3& cell, vtkm::Vec3f_32& point) const { const vtkm::Id pointIndex = - static_cast(this)->Conn.LogicalToFlatFromIndex(cell); + static_cast(this)->Conn.LogicalToFlatIncidentIndex(cell); point = static_cast(this)->Coordinates.Get(pointIndex); } }; From 4064a3bd06f33c33fc42125d36239ce8a2df244f Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 22 May 2023 13:03:23 -0600 Subject: [PATCH 19/38] Allow ComputeMoments to operate on any scalar field Previously, the `ComputeMoments` filter only operated on a finite set of array types as its input field. This included a prescribed list of `Vec` sizes for the input. The filter has been updated to use more generic interfaces to the field's array (and float fallback) to enable the computation of moments on any type of scalar field. --- .../changelog/compute-moments-any-vec-size.md | 7 ++ .../image_processing/ComputeMoments.cxx | 15 +--- .../image_processing/worklet/ComputeMoments.h | 79 +++++++++++++------ 3 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 docs/changelog/compute-moments-any-vec-size.md diff --git a/docs/changelog/compute-moments-any-vec-size.md b/docs/changelog/compute-moments-any-vec-size.md new file mode 100644 index 000000000..75efc6c9f --- /dev/null +++ b/docs/changelog/compute-moments-any-vec-size.md @@ -0,0 +1,7 @@ +# ComputeMoments filter now operates on any scalar field + +Previously, the `ComputeMoments` filter only operated on a finite set of +array types as its input field. This included a prescribed list of `Vec` +sizes for the input. The filter has been updated to use more generic +interfaces to the field's array (and float fallback) to enable the +computation of moments on any type of scalar field. diff --git a/vtkm/filter/image_processing/ComputeMoments.cxx b/vtkm/filter/image_processing/ComputeMoments.cxx index 78499739c..96f350694 100644 --- a/vtkm/filter/image_processing/ComputeMoments.cxx +++ b/vtkm/filter/image_processing/ComputeMoments.cxx @@ -21,18 +21,6 @@ namespace filter { namespace image_processing { -using SupportedTypes = vtkm::List, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec, - vtkm::Vec>; VTKM_CONT ComputeMoments::ComputeMoments() { @@ -53,8 +41,7 @@ VTKM_CONT vtkm::cont::DataSet ComputeMoments::DoExecute(const vtkm::cont::DataSe auto resolveType = [&](const auto& concrete) { worklet.Run(input.GetCellSet(), concrete, this->Order, output); }; - field.GetData().CastAndCallForTypesWithFloatFallback( - resolveType); + this->CastAndCallVariableVecField(field, resolveType); return output; } diff --git a/vtkm/filter/image_processing/worklet/ComputeMoments.h b/vtkm/filter/image_processing/worklet/ComputeMoments.h index d99722496..283989abe 100644 --- a/vtkm/filter/image_processing/worklet/ComputeMoments.h +++ b/vtkm/filter/image_processing/worklet/ComputeMoments.h @@ -15,6 +15,9 @@ #include #include +#include +#include +#include #include #include #include @@ -54,13 +57,19 @@ public: using ExecutionSignature = void(_2, Boundary, _3); - template + template VTKM_EXEC void operator()(const NeighIn& image, const vtkm::exec::BoundaryState& boundary, - T& moment) const + TOut& moment) const { - // TODO: type safety and numerical precision - auto sum = vtkm::TypeTraits::ZeroInitialization(); + using ComponentType = typename TOut::ComponentType; + const vtkm::IdComponent numComponents = moment.GetNumberOfComponents(); + + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] = vtkm::TypeTraits::ZeroInitialization(); + } // Clamp the radius to the dataset bounds (discard out-of-bounds points). const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete); @@ -85,13 +94,23 @@ public: if (vtkm::Dot(radius, radius) <= 1) { - sum += - static_cast(vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q) * image.Get(i, j, 0)); + ComponentType multiplier = + static_cast(vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q)); + auto inputField = image.Get(i, j, 0); + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] += multiplier * inputField[componentI]; + } } } } - moment = T(sum * this->SpacingProduct); + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] *= static_cast(this->SpacingProduct); + } } private: @@ -126,13 +145,19 @@ public: using ExecutionSignature = void(_2, Boundary, _3); - template + template VTKM_EXEC void operator()(const NeighIn& image, const vtkm::exec::BoundaryState& boundary, - T& moment) const + TOut& moment) const { - // TODO: type safety and numerical precision - auto sum = vtkm::TypeTraits::ZeroInitialization(); + using ComponentType = typename TOut::ComponentType; + const vtkm::IdComponent numComponents = moment.GetNumberOfComponents(); + + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] = vtkm::TypeTraits::ZeroInitialization(); + } // Clamp the radius to the dataset bounds (discard out-of-bounds points). const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete); @@ -165,14 +190,24 @@ public: if (vtkm::Dot(radius, radius) <= 1) { - sum += static_cast(vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q) * - vtkm::Pow(radius[2], r) * image.Get(i, j, k)); + ComponentType multiplier = static_cast( + vtkm::Pow(radius[0], p) * vtkm::Pow(radius[1], q) * vtkm::Pow(radius[2], r)); + auto inputField = image.Get(i, j, k); + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] += multiplier * inputField[componentI]; + } } } } } - moment = T(sum * this->SpacingProduct); + // For variable sized Vecs, need to iterate over each component. + for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI) + { + moment[componentI] *= static_cast(this->SpacingProduct); + } } private: @@ -195,9 +230,9 @@ public: class ResolveUnknownCellSet { public: - template + template void operator()(const vtkm::cont::CellSetStructured<2>& input, - const vtkm::cont::ArrayHandle& pixels, + const vtkm::cont::ArrayHandleRecombineVec& pixels, vtkm::Vec3f spacing, vtkm::Float64 radius, int maxOrder, @@ -212,7 +247,7 @@ public: { const int q = order - p; - vtkm::cont::ArrayHandle moments; + vtkm::cont::ArrayHandleRuntimeVec moments{ pixels.GetNumberOfComponents() }; DispatcherType dispatcher(WorkletType{ spacing, radius, p, q }); dispatcher.Invoke(input, pixels, moments); @@ -226,9 +261,9 @@ public: } } - template + template void operator()(const vtkm::cont::CellSetStructured<3>& input, - const vtkm::cont::ArrayHandle& pixels, + const vtkm::cont::ArrayHandleRecombineVec& pixels, vtkm::Vec3f spacing, vtkm::Float64 radius, int maxOrder, @@ -246,7 +281,7 @@ public: { const int p = order - r - q; - vtkm::cont::ArrayHandle moments; + vtkm::cont::ArrayHandleRuntimeVec moments{ pixels.GetNumberOfComponents() }; DispatcherType dispatcher(WorkletType{ spacing, radius, p, q, r }); dispatcher.Invoke(input, pixels, moments); @@ -263,9 +298,9 @@ public: } }; - template + template void Run(const vtkm::cont::UnknownCellSet& input, - const vtkm::cont::ArrayHandle& pixels, + const vtkm::cont::ArrayHandleRecombineVec& pixels, int maxOrder, vtkm::cont::DataSet& output) const { From 10bcf618f633590b90e7dde7f8f4f335bff00f6e Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Mon, 5 Jun 2023 09:02:27 -0600 Subject: [PATCH 20/38] non-virtual color table annotations --- vtkm/rendering/ColorBarAnnotation.cxx | 5 +---- vtkm/rendering/ColorBarAnnotation.h | 8 +++----- vtkm/rendering/ColorLegendAnnotation.cxx | 8 +++----- vtkm/rendering/ColorLegendAnnotation.h | 11 +++++------ 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/vtkm/rendering/ColorBarAnnotation.cxx b/vtkm/rendering/ColorBarAnnotation.cxx index f184b4bf0..500f9686b 100644 --- a/vtkm/rendering/ColorBarAnnotation.cxx +++ b/vtkm/rendering/ColorBarAnnotation.cxx @@ -20,12 +20,9 @@ ColorBarAnnotation::ColorBarAnnotation() : ColorTable(vtkm::ColorSpace::Lab) , Position(vtkm::Range(-0.88, +0.88), vtkm::Range(+0.87, +0.92), vtkm::Range(0, 0)) , Horizontal(true) - , FieldName("") { } -ColorBarAnnotation::~ColorBarAnnotation() {} - void ColorBarAnnotation::SetFieldName(const std::string& fieldName) { FieldName = fieldName; @@ -83,7 +80,7 @@ void ColorBarAnnotation::Render(const vtkm::rendering::Camera& camera, this->Axis.SetMinorTickSize(0, 0, 0); // no minor ticks this->Axis.Render(camera, worldAnnotator, canvas); - if (FieldName != "") + if (!FieldName.empty()) { vtkm::Vec2f_32 labelPos; if (Horizontal) diff --git a/vtkm/rendering/ColorBarAnnotation.h b/vtkm/rendering/ColorBarAnnotation.h index b8c8d4aae..76426cd4f 100644 --- a/vtkm/rendering/ColorBarAnnotation.h +++ b/vtkm/rendering/ColorBarAnnotation.h @@ -35,8 +35,6 @@ protected: public: ColorBarAnnotation(); - virtual ~ColorBarAnnotation(); - VTKM_CONT void SetColorTable(const vtkm::cont::ColorTable& colorTable) { this->ColorTable = colorTable; } @@ -56,9 +54,9 @@ public: VTKM_CONT void SetPosition(const vtkm::Bounds& position); - virtual void Render(const vtkm::rendering::Camera& camera, - const vtkm::rendering::WorldAnnotator& worldAnnotator, - vtkm::rendering::Canvas& canvas); + void Render(const vtkm::rendering::Camera& camera, + const vtkm::rendering::WorldAnnotator& worldAnnotator, + vtkm::rendering::Canvas& canvas); }; } } //namespace vtkm::rendering diff --git a/vtkm/rendering/ColorLegendAnnotation.cxx b/vtkm/rendering/ColorLegendAnnotation.cxx index 2adb86b80..654824903 100644 --- a/vtkm/rendering/ColorLegendAnnotation.cxx +++ b/vtkm/rendering/ColorLegendAnnotation.cxx @@ -21,8 +21,6 @@ ColorLegendAnnotation::ColorLegendAnnotation() this->LabelColor = vtkm::rendering::Color::white; } -ColorLegendAnnotation::~ColorLegendAnnotation() {} - void ColorLegendAnnotation::Clear() { this->Labels.clear(); @@ -42,9 +40,9 @@ void ColorLegendAnnotation::Render(const vtkm::rendering::Camera& camera, vtkm::Float32 l = -0.95f, r = -0.90f; vtkm::Float32 b = +0.90f, t = +0.95f; - for (unsigned int i = 0; i < this->ColorSwatchList.size(); ++i) + for (auto& color : this->ColorSwatchList) { - canvas.AddColorSwatch(l, b, l, t, r, t, r, b, this->ColorSwatchList[i]); + canvas.AddColorSwatch(l, b, l, t, r, t, r, b, color); b -= 0.07f; t -= 0.07f; } @@ -58,7 +56,7 @@ void ColorLegendAnnotation::Render(const vtkm::rendering::Camera& camera, while (this->Annot.size() < this->Labels.size()) { this->Annot.push_back( - std::unique_ptr(new vtkm::rendering::TextAnnotationScreen( + std::make_unique(vtkm::rendering::TextAnnotationScreen( "test", this->LabelColor, this->FontScale, vtkm::Vec2f_32(0, 0), 0))); } diff --git a/vtkm/rendering/ColorLegendAnnotation.h b/vtkm/rendering/ColorLegendAnnotation.h index ca3cf221c..06e856b4f 100644 --- a/vtkm/rendering/ColorLegendAnnotation.h +++ b/vtkm/rendering/ColorLegendAnnotation.h @@ -34,7 +34,6 @@ private: public: ColorLegendAnnotation(); - ~ColorLegendAnnotation(); ColorLegendAnnotation(const ColorLegendAnnotation&) = delete; ColorLegendAnnotation& operator=(const ColorLegendAnnotation&) = delete; @@ -46,13 +45,13 @@ public: void SetLabelFontScale(vtkm::Float32 s) { this->FontScale = s; - for (unsigned int i = 0; i < this->Annot.size(); i++) - this->Annot[i]->SetScale(s); + for (auto& annot : this->Annot) + annot->SetScale(s); } - virtual void Render(const vtkm::rendering::Camera&, - const vtkm::rendering::WorldAnnotator& annotator, - vtkm::rendering::Canvas& canvas); + void Render(const vtkm::rendering::Camera&, + const vtkm::rendering::WorldAnnotator& annotator, + vtkm::rendering::Canvas& canvas); }; } } //namespace vtkm::rendering From 85b4b18fca22c3f318c7567c675a4389c3b313de Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Mon, 5 Jun 2023 11:20:49 -0600 Subject: [PATCH 21/38] properly call make_unique --- vtkm/rendering/ColorLegendAnnotation.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vtkm/rendering/ColorLegendAnnotation.cxx b/vtkm/rendering/ColorLegendAnnotation.cxx index 654824903..5763140ca 100644 --- a/vtkm/rendering/ColorLegendAnnotation.cxx +++ b/vtkm/rendering/ColorLegendAnnotation.cxx @@ -55,9 +55,8 @@ void ColorLegendAnnotation::Render(const vtkm::rendering::Camera& camera, while (this->Annot.size() < this->Labels.size()) { - this->Annot.push_back( - std::make_unique(vtkm::rendering::TextAnnotationScreen( - "test", this->LabelColor, this->FontScale, vtkm::Vec2f_32(0, 0), 0))); + this->Annot.push_back(std::make_unique( + "test", this->LabelColor, this->FontScale, vtkm::Vec2f_32(0, 0), 0)); } for (unsigned int i = 0; i < this->Annot.size(); ++i) From c8caecfefc14f092daa535b6ef00d8196247de40 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Mon, 5 Jun 2023 13:08:38 -0600 Subject: [PATCH 22/38] try to supress warning on windows --- vtkm/rendering/ColorLegendAnnotation.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtkm/rendering/ColorLegendAnnotation.cxx b/vtkm/rendering/ColorLegendAnnotation.cxx index 5763140ca..49f0beea7 100644 --- a/vtkm/rendering/ColorLegendAnnotation.cxx +++ b/vtkm/rendering/ColorLegendAnnotation.cxx @@ -56,7 +56,7 @@ void ColorLegendAnnotation::Render(const vtkm::rendering::Camera& camera, while (this->Annot.size() < this->Labels.size()) { this->Annot.push_back(std::make_unique( - "test", this->LabelColor, this->FontScale, vtkm::Vec2f_32(0, 0), 0)); + "test", this->LabelColor, this->FontScale, vtkm::Vec2f_32(0, 0))); } for (unsigned int i = 0; i < this->Annot.size(); ++i) From 7bbda42fe50989a6c7ffbc4a295f822e21dae790 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Mon, 12 Jun 2023 14:02:47 -0600 Subject: [PATCH 23/38] clean up Annontations --- vtkm/rendering/AxisAnnotation.cxx | 14 ++++--------- vtkm/rendering/AxisAnnotation.h | 22 ++++++++++---------- vtkm/rendering/AxisAnnotation2D.cxx | 19 +++++++---------- vtkm/rendering/AxisAnnotation2D.h | 7 ++----- vtkm/rendering/AxisAnnotation3D.cxx | 24 +++++++++------------- vtkm/rendering/AxisAnnotation3D.h | 10 ++++----- vtkm/rendering/TextAnnotation.cxx | 2 +- vtkm/rendering/TextAnnotationBillboard.cxx | 2 -- vtkm/rendering/TextAnnotationBillboard.h | 2 -- vtkm/rendering/TextAnnotationScreen.cxx | 2 -- vtkm/rendering/TextAnnotationScreen.h | 2 -- vtkm/rendering/WorldAnnotator.cxx | 2 +- vtkm/rendering/WorldAnnotator.h | 4 ++-- 13 files changed, 42 insertions(+), 70 deletions(-) diff --git a/vtkm/rendering/AxisAnnotation.cxx b/vtkm/rendering/AxisAnnotation.cxx index dae6d8e26..2b239b2bf 100644 --- a/vtkm/rendering/AxisAnnotation.cxx +++ b/vtkm/rendering/AxisAnnotation.cxx @@ -10,8 +10,6 @@ #include -#include - namespace vtkm { namespace rendering @@ -37,7 +35,7 @@ void AxisAnnotation::CalculateTicks(const vtkm::Range& range, bool minor, std::vector& positions, std::vector& proportions, - int modifyTickQuantity) const + int modifyTickQuantity) { positions.clear(); proportions.clear(); @@ -144,7 +142,7 @@ void AxisAnnotation::CalculateTicks(const vtkm::Range& range, void AxisAnnotation::CalculateTicksLogarithmic(const vtkm::Range& range, bool minor, std::vector& positions, - std::vector& proportions) const + std::vector& proportions) { positions.clear(); proportions.clear(); @@ -167,7 +165,7 @@ void AxisAnnotation::CalculateTicksLogarithmic(const vtkm::Range& range, last_log = first_log + 1; } vtkm::Float64 diff_log = last_log - first_log; - vtkm::Int32 step = vtkm::Int32((diff_log + 9) / 10); + auto step = vtkm::Int32((diff_log + 9) / 10); if (minor) { @@ -175,7 +173,7 @@ void AxisAnnotation::CalculateTicksLogarithmic(const vtkm::Range& range, last_log += step; } - for (vtkm::Int32 i = vtkm::Int32(first_log); i <= last_log; i += step) + for (auto i = vtkm::Int32(first_log); i <= last_log; i += step) { vtkm::Float64 logpos = i; vtkm::Float64 pos = vtkm::Pow(10, logpos); @@ -229,9 +227,5 @@ void AxisAnnotation::CalculateTicksLogarithmic(const vtkm::Range& range, } } } - -AxisAnnotation::AxisAnnotation() {} - -AxisAnnotation::~AxisAnnotation() {} } } // namespace vtkm::rendering diff --git a/vtkm/rendering/AxisAnnotation.h b/vtkm/rendering/AxisAnnotation.h index 2fac7e79b..20421b87b 100644 --- a/vtkm/rendering/AxisAnnotation.h +++ b/vtkm/rendering/AxisAnnotation.h @@ -24,20 +24,20 @@ namespace rendering class VTKM_RENDERING_EXPORT AxisAnnotation { protected: - void CalculateTicks(const vtkm::Range& range, - bool minor, - std::vector& positions, - std::vector& proportions, - int modifyTickQuantity) const; - void CalculateTicksLogarithmic(const vtkm::Range& range, - bool minor, - std::vector& positions, - std::vector& proportions) const; + static void CalculateTicks(const vtkm::Range& range, + bool minor, + std::vector& positions, + std::vector& proportions, + int modifyTickQuantity); + static void CalculateTicksLogarithmic(const vtkm::Range& range, + bool minor, + std::vector& positions, + std::vector& proportions); public: - AxisAnnotation(); + AxisAnnotation() = default; - virtual ~AxisAnnotation(); + virtual ~AxisAnnotation() = default; virtual void Render(const vtkm::rendering::Camera& camera, const vtkm::rendering::WorldAnnotator& worldAnnotator, diff --git a/vtkm/rendering/AxisAnnotation2D.cxx b/vtkm/rendering/AxisAnnotation2D.cxx index b0acecdd6..f31daf2c5 100644 --- a/vtkm/rendering/AxisAnnotation2D.cxx +++ b/vtkm/rendering/AxisAnnotation2D.cxx @@ -20,7 +20,6 @@ namespace rendering { AxisAnnotation2D::AxisAnnotation2D() - : AxisAnnotation() { this->AlignH = TextAnnotation::HCenter; this->AlignV = TextAnnotation::VCenter; @@ -31,8 +30,6 @@ AxisAnnotation2D::AxisAnnotation2D() this->MoreOrLessTickAdjustment = 0; } -AxisAnnotation2D::~AxisAnnotation2D() {} - void AxisAnnotation2D::SetRangeForAutoTicks(const Range& range) { this->TickRange = range; @@ -84,12 +81,11 @@ void AxisAnnotation2D::Render(const vtkm::rendering::Camera& camera, canvas.AddLine(this->PosX0, this->PosY0, this->PosX1, this->PosY1, this->LineWidth, this->Color); // major ticks - unsigned int nmajor = (unsigned int)this->ProportionsMajor.size(); + auto nmajor = (unsigned int)this->ProportionsMajor.size(); while (this->Labels.size() < nmajor) { - this->Labels.push_back( - std::unique_ptr(new vtkm::rendering::TextAnnotationScreen( - "test", this->Color, this->FontScale, vtkm::Vec2f_32(0, 0), 0))); + this->Labels.push_back(std::make_unique( + "test", this->Color, this->FontScale, vtkm::Vec2f_32(0, 0), 0)); } std::stringstream numberToString; @@ -116,8 +112,7 @@ void AxisAnnotation2D::Render(const vtkm::rendering::Camera& camera, this->Labels[i]->SetText(numberToString.str()); //if (fabs(this->PositionsMajor[i]) < 1e-10) // this->Labels[i]->SetText("0"); - TextAnnotation* tempBase = this->Labels[i].get(); - TextAnnotationScreen* tempDerived = static_cast(tempBase); + auto* tempDerived = dynamic_cast(this->Labels[i].get()); tempDerived->SetPosition(vtkm::Float32(xs), vtkm::Float32(ys)); this->Labels[i]->SetAlignment(this->AlignH, this->AlignV); @@ -126,7 +121,7 @@ void AxisAnnotation2D::Render(const vtkm::rendering::Camera& camera, // minor ticks if (this->MinorTickSizeX != 0 || this->MinorTickSizeY != 0) { - unsigned int nminor = (unsigned int)this->ProportionsMinor.size(); + auto nminor = (unsigned int)this->ProportionsMinor.size(); for (unsigned int i = 0; i < nminor; ++i) { vtkm::Float64 xc = this->PosX0 + (this->PosX1 - this->PosX0) * this->ProportionsMinor[i]; @@ -140,9 +135,9 @@ void AxisAnnotation2D::Render(const vtkm::rendering::Camera& camera, } } - for (unsigned int i = 0; i < nmajor; ++i) + for (auto& label : this->Labels) { - this->Labels[i]->Render(camera, worldAnnotator, canvas); + label->Render(camera, worldAnnotator, canvas); } } } diff --git a/vtkm/rendering/AxisAnnotation2D.h b/vtkm/rendering/AxisAnnotation2D.h index 383678ce2..cecf69aba 100644 --- a/vtkm/rendering/AxisAnnotation2D.h +++ b/vtkm/rendering/AxisAnnotation2D.h @@ -41,7 +41,6 @@ protected: TextAnnotation::HorizontalAlignment AlignH; TextAnnotation::VerticalAlignment AlignV; std::vector> Labels; - // std::vector Labels; std::vector PositionsMajor; std::vector ProportionsMajor; @@ -54,8 +53,6 @@ protected: public: AxisAnnotation2D(); - ~AxisAnnotation2D(); - AxisAnnotation2D(const AxisAnnotation2D&) = delete; AxisAnnotation2D& operator=(const AxisAnnotation2D&) = delete; @@ -104,8 +101,8 @@ public: void SetLabelFontScale(vtkm::Float32 s) { this->FontScale = s; - for (unsigned int i = 0; i < this->Labels.size(); i++) - this->Labels[i]->SetScale(s); + for (auto& label : this->Labels) + label->SetScale(s); } void SetRangeForAutoTicks(const vtkm::Range& range); diff --git a/vtkm/rendering/AxisAnnotation3D.cxx b/vtkm/rendering/AxisAnnotation3D.cxx index 2168d98c2..b0888b320 100644 --- a/vtkm/rendering/AxisAnnotation3D.cxx +++ b/vtkm/rendering/AxisAnnotation3D.cxx @@ -10,6 +10,8 @@ #include +#include + namespace vtkm { namespace rendering @@ -36,8 +38,6 @@ AxisAnnotation3D::AxisAnnotation3D() { } -AxisAnnotation3D::~AxisAnnotation3D() {} - void AxisAnnotation3D::SetTickInvert(bool x, bool y, bool z) { this->Invert[0] = x ? +1.0f : -1.0f; @@ -48,9 +48,9 @@ void AxisAnnotation3D::SetTickInvert(bool x, bool y, bool z) void AxisAnnotation3D::SetLabelFontScale(Float64 s) { this->FontScale = s; - for (unsigned int i = 0; i < this->Labels.size(); i++) + for (auto& label : this->Labels) { - this->Labels[i]->SetScale(vtkm::Float32(s)); + label->SetScale(vtkm::Float32(s)); } } @@ -65,12 +65,11 @@ void AxisAnnotation3D::Render(const Camera& camera, std::vector proportions; // major ticks CalculateTicks(this->Range, false, positions, proportions, this->MoreOrLessTickAdjustment); - unsigned int nmajor = (unsigned int)proportions.size(); + auto nmajor = (unsigned int)proportions.size(); while (this->Labels.size() < nmajor) { - this->Labels.push_back( - std::unique_ptr(new vtkm::rendering::TextAnnotationBillboard( - "test", this->Color, vtkm::Float32(this->FontScale), vtkm::Vec3f_32(0, 0, 0), 0))); + this->Labels.push_back(std::make_unique( + "test", this->Color, vtkm::Float32(this->FontScale), vtkm::Vec3f_32(0, 0, 0), 0)); } std::stringstream numberToString; @@ -144,15 +143,12 @@ void AxisAnnotation3D::Render(const Camera& camera, this->Labels[i]->SetPosition(vtkm::Float32(tickPos[0] - tickSize[0]), vtkm::Float32(tickPos[1] - tickSize[1]), vtkm::Float32(tickPos[2] - tickSize[2])); - vtkm::Vec3f_32 pp(vtkm::Float32(tickPos[0] - tickSize[0]), - vtkm::Float32(tickPos[1] - tickSize[1]), - vtkm::Float32(tickPos[2] - tickSize[2])); this->Labels[i]->SetAlignment(TextAnnotation::HCenter, TextAnnotation::VCenter); } // minor ticks CalculateTicks(this->Range, true, positions, proportions, this->MoreOrLessTickAdjustment); - unsigned int nminor = (unsigned int)proportions.size(); + auto nminor = (unsigned int)proportions.size(); for (unsigned int i = 0; i < nminor; ++i) { vtkm::Vec3f_64 tickPos = proportions[i] * (this->Point1 - this->Point0) + this->Point0; @@ -197,9 +193,9 @@ void AxisAnnotation3D::Render(const Camera& camera, } } - for (unsigned int i = 0; i < nmajor; ++i) + for (auto& label : this->Labels) { - this->Labels[i]->Render(camera, worldAnnotator, canvas); + label->Render(camera, worldAnnotator, canvas); } } } diff --git a/vtkm/rendering/AxisAnnotation3D.h b/vtkm/rendering/AxisAnnotation3D.h index 71d8884e0..193fd9ec0 100644 --- a/vtkm/rendering/AxisAnnotation3D.h +++ b/vtkm/rendering/AxisAnnotation3D.h @@ -22,7 +22,7 @@ #include #include -#include +#include namespace vtkm { @@ -49,8 +49,6 @@ protected: public: AxisAnnotation3D(); - ~AxisAnnotation3D(); - AxisAnnotation3D(const AxisAnnotation3D&) = delete; AxisAnnotation3D& operator=(const AxisAnnotation3D&) = delete; @@ -111,9 +109,9 @@ public: this->SetRange(vtkm::Range(lower, upper)); } - virtual void Render(const vtkm::rendering::Camera& camera, - const vtkm::rendering::WorldAnnotator& worldAnnotator, - vtkm::rendering::Canvas& canvas) override; + void Render(const vtkm::rendering::Camera& camera, + const vtkm::rendering::WorldAnnotator& worldAnnotator, + vtkm::rendering::Canvas& canvas) override; }; } } //namespace vtkm::rendering diff --git a/vtkm/rendering/TextAnnotation.cxx b/vtkm/rendering/TextAnnotation.cxx index 0f0f977a5..a5b9b2bf5 100644 --- a/vtkm/rendering/TextAnnotation.cxx +++ b/vtkm/rendering/TextAnnotation.cxx @@ -25,7 +25,7 @@ TextAnnotation::TextAnnotation(const std::string& text, { } -TextAnnotation::~TextAnnotation() {} +TextAnnotation::~TextAnnotation() = default; void TextAnnotation::SetText(const std::string& text) { diff --git a/vtkm/rendering/TextAnnotationBillboard.cxx b/vtkm/rendering/TextAnnotationBillboard.cxx index 0274326fa..7b9daee58 100644 --- a/vtkm/rendering/TextAnnotationBillboard.cxx +++ b/vtkm/rendering/TextAnnotationBillboard.cxx @@ -28,8 +28,6 @@ TextAnnotationBillboard::TextAnnotationBillboard(const std::string& text, { } -TextAnnotationBillboard::~TextAnnotationBillboard() {} - void TextAnnotationBillboard::SetPosition(const vtkm::Vec3f_32& position) { this->Position = position; diff --git a/vtkm/rendering/TextAnnotationBillboard.h b/vtkm/rendering/TextAnnotationBillboard.h index 7b8b5f834..c23c09983 100644 --- a/vtkm/rendering/TextAnnotationBillboard.h +++ b/vtkm/rendering/TextAnnotationBillboard.h @@ -30,8 +30,6 @@ public: const vtkm::Vec3f_32& position, vtkm::Float32 angleDegrees = 0); - ~TextAnnotationBillboard(); - void SetPosition(const vtkm::Vec3f_32& position); void SetPosition(vtkm::Float32 posx, vtkm::Float32 posy, vtkm::Float32 posz); diff --git a/vtkm/rendering/TextAnnotationScreen.cxx b/vtkm/rendering/TextAnnotationScreen.cxx index 2f87b845a..bb871bc1e 100644 --- a/vtkm/rendering/TextAnnotationScreen.cxx +++ b/vtkm/rendering/TextAnnotationScreen.cxx @@ -26,8 +26,6 @@ TextAnnotationScreen::TextAnnotationScreen(const std::string& text, { } -TextAnnotationScreen::~TextAnnotationScreen() {} - void TextAnnotationScreen::SetPosition(const vtkm::Vec2f_32& position) { this->Position = position; diff --git a/vtkm/rendering/TextAnnotationScreen.h b/vtkm/rendering/TextAnnotationScreen.h index 8bd50659f..2ce80bc26 100644 --- a/vtkm/rendering/TextAnnotationScreen.h +++ b/vtkm/rendering/TextAnnotationScreen.h @@ -30,8 +30,6 @@ public: const vtkm::Vec2f_32& position, vtkm::Float32 angleDegrees = 0); - ~TextAnnotationScreen(); - void SetPosition(const vtkm::Vec2f_32& position); void SetPosition(vtkm::Float32 posx, vtkm::Float32 posy); diff --git a/vtkm/rendering/WorldAnnotator.cxx b/vtkm/rendering/WorldAnnotator.cxx index 430693713..3e15f1492 100644 --- a/vtkm/rendering/WorldAnnotator.cxx +++ b/vtkm/rendering/WorldAnnotator.cxx @@ -51,7 +51,7 @@ void WorldAnnotator::AddText(const vtkm::Vec3f_32& origin, const vtkm::Vec2f_32& anchor, const vtkm::rendering::Color& color, const std::string& text, - const vtkm::Float32 depth) const + vtkm::Float32 depth) const { vtkm::Vec3f_32 n = vtkm::Cross(right, up); vtkm::Normalize(n); diff --git a/vtkm/rendering/WorldAnnotator.h b/vtkm/rendering/WorldAnnotator.h index d4e673c1d..e149fd60f 100644 --- a/vtkm/rendering/WorldAnnotator.h +++ b/vtkm/rendering/WorldAnnotator.h @@ -27,7 +27,7 @@ class Canvas; class VTKM_RENDERING_EXPORT WorldAnnotator { public: - WorldAnnotator(const vtkm::rendering::Canvas* canvas); + explicit WorldAnnotator(const vtkm::rendering::Canvas* canvas); void AddLine(const vtkm::Vec3f_64& point0, const vtkm::Vec3f_64& point1, @@ -63,7 +63,7 @@ public: const vtkm::Vec2f_32& anchor, const vtkm::rendering::Color& color, const std::string& text, - const vtkm::Float32 depth = 0.f) const; + vtkm::Float32 depth = 0.f) const; VTKM_CONT void AddText(vtkm::Float32 originX, From 362efb637c4cb6a5ece0c970b95c5c412d206b79 Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Wed, 14 Jun 2023 10:04:43 -0600 Subject: [PATCH 24/38] try to surpress warning for window --- vtkm/rendering/AxisAnnotation2D.cxx | 2 +- vtkm/rendering/AxisAnnotation3D.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vtkm/rendering/AxisAnnotation2D.cxx b/vtkm/rendering/AxisAnnotation2D.cxx index f31daf2c5..879e67427 100644 --- a/vtkm/rendering/AxisAnnotation2D.cxx +++ b/vtkm/rendering/AxisAnnotation2D.cxx @@ -85,7 +85,7 @@ void AxisAnnotation2D::Render(const vtkm::rendering::Camera& camera, while (this->Labels.size() < nmajor) { this->Labels.push_back(std::make_unique( - "test", this->Color, this->FontScale, vtkm::Vec2f_32(0, 0), 0)); + "test", this->Color, this->FontScale, vtkm::Vec2f_32(0, 0))); } std::stringstream numberToString; diff --git a/vtkm/rendering/AxisAnnotation3D.cxx b/vtkm/rendering/AxisAnnotation3D.cxx index b0888b320..ff40f9275 100644 --- a/vtkm/rendering/AxisAnnotation3D.cxx +++ b/vtkm/rendering/AxisAnnotation3D.cxx @@ -69,7 +69,7 @@ void AxisAnnotation3D::Render(const Camera& camera, while (this->Labels.size() < nmajor) { this->Labels.push_back(std::make_unique( - "test", this->Color, vtkm::Float32(this->FontScale), vtkm::Vec3f_32(0, 0, 0), 0)); + "test", this->Color, vtkm::Float32(this->FontScale), vtkm::Vec3f_32(0, 0, 0))); } std::stringstream numberToString; From cb0f8069885c22b3a8c1359dc245054efa484751 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 15 Jun 2023 17:41:14 -0400 Subject: [PATCH 25/38] ci,ascent: disable git-lfs pre-push hook --- .gitlab/ci/config/ecpci-push-branch.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab/ci/config/ecpci-push-branch.sh b/.gitlab/ci/config/ecpci-push-branch.sh index 1df586417..41fe9bcab 100755 --- a/.gitlab/ci/config/ecpci-push-branch.sh +++ b/.gitlab/ci/config/ecpci-push-branch.sh @@ -1,4 +1,3 @@ #!/bin/bash -ex -git lfs uninstall -git -c http.sslVerify=false push -f "$1" "HEAD:refs/heads/${2}" +git -c http.sslVerify=false push --no-verify -f "$1" "HEAD:refs/heads/${2}" From 46a613d183e758ec89b5320f3d7534c8088f57e8 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 7 Jun 2023 17:15:33 -0400 Subject: [PATCH 26/38] Speed up compilation of ArrayRangeCompute.cxx The file `ArrayRangeCompute.cxx` was taking a long time to compile with some device compilers. This is because it precompiles the range computation for many types of array structures. It thus compiled the same operation many times over. The new implementation compiles just as many cases. However, the compilation is split into many different translation units using the instantiations feature of VTK-m's configuration. Although this rarely reduces the overall CPU time spent during compiling, it prevents parallel compiles from waiting for this one build to complete. It also avoids potential issues with compilers running out of resources as it tries to build a monolithic file. --- CMake/VTKmWrappers.cmake | 4 + docs/changelog/array-range-instantiations.md | 14 ++ vtkm/cont/ArrayRangeComputeTemplate.h | 156 ++++++++++++++++++- vtkm/cont/CMakeLists.txt | 8 + 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/array-range-instantiations.md diff --git a/CMake/VTKmWrappers.cmake b/CMake/VTKmWrappers.cmake index 10ba21e06..c1833a374 100644 --- a/CMake/VTKmWrappers.cmake +++ b/CMake/VTKmWrappers.cmake @@ -658,6 +658,10 @@ function(vtkm_add_instantiations instantiations_list) set(file_template_source ${instantiations_file}) endif() + set_property(DIRECTORY + APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS ${instantiations_file}) + # Extract explicit instantiations _vtkm_extract_instantiations(instantiations ${instantiations_file}) diff --git a/docs/changelog/array-range-instantiations.md b/docs/changelog/array-range-instantiations.md new file mode 100644 index 000000000..1bf4e98ff --- /dev/null +++ b/docs/changelog/array-range-instantiations.md @@ -0,0 +1,14 @@ +# Sped up compilation of ArrayRangeCompute.cxx + +The file `ArrayRangeCompute.cxx` was taking a long time to compile with +some device compilers. This is because it precompiles the range computation +for many types of array structures. It thus compiled the same operation +many times over. + +The new implementation compiles just as many cases. However, the +compilation is split into many different translation units using the +instantiations feature of VTK-m's configuration. Although this rarely +reduces the overall CPU time spent during compiling, it prevents parallel +compiles from waiting for this one build to complete. It also avoids +potential issues with compilers running out of resources as it tries to +build a monolithic file. diff --git a/vtkm/cont/ArrayRangeComputeTemplate.h b/vtkm/cont/ArrayRangeComputeTemplate.h index aeab8c3c5..8e29f1166 100644 --- a/vtkm/cont/ArrayRangeComputeTemplate.h +++ b/vtkm/cont/ArrayRangeComputeTemplate.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include @@ -114,7 +116,7 @@ struct ArrayRangeComputeImpl template -inline vtkm::cont::ArrayHandle ArrayRangeComputeTemplate( +vtkm::cont::ArrayHandle ArrayRangeComputeTemplate( const ArrayHandleType& input, vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{}) { @@ -134,4 +136,156 @@ inline vtkm::cont::ArrayHandle ArrayRangeCompute( } } // namespace vtkm::cont +#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(modifiers, ...) \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle& input, \ + vtkm::cont::DeviceAdapterId device) + +#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(modifiers, N, ...) \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& input, \ + vtkm::cont::DeviceAdapterId device); \ + modifiers vtkm::cont::ArrayHandle vtkm::cont::ArrayRangeComputeTemplate( \ + const vtkm::cont::ArrayHandle, __VA_ARGS__>& \ + input, \ + vtkm::cont::DeviceAdapterId device) + +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT, + vtkm::cont::StorageTagBasic); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 2, + vtkm::cont::StorageTagBasic); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 3, + vtkm::cont::StorageTagBasic); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 4, + vtkm::cont::StorageTagBasic); +VTKM_INSTANTIATION_END + +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 2, + vtkm::cont::StorageTagSOA); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 3, + vtkm::cont::StorageTagSOA); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 4, + vtkm::cont::StorageTagSOA); +VTKM_INSTANTIATION_END + +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN( + extern template VTKM_CONT_TEMPLATE_EXPORT, + 3, + vtkm::cont::StorageTagCartesianProduct); +VTKM_INSTANTIATION_END + +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT, + vtkm::cont::StorageTagConstant); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 2, + vtkm::cont::StorageTagConstant); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 3, + vtkm::cont::StorageTagConstant); +VTKM_INSTANTIATION_END +VTKM_INSTANTIATION_BEGIN +VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT, + 4, + vtkm::cont::StorageTagConstant); +VTKM_INSTANTIATION_END + #endif //vtk_m_cont_ArrayRangeComputeTemplate_h diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 9e824ff95..c5de8ac6f 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -263,6 +263,14 @@ vtkm_install_headers(vtkm/cont ${VTKm_BINARY_INCLUDE_DIR}/${kit_dir}/DefaultTypes.h ) +#----------------------------------------------------------------------------- +# Some operations are pre-compiled for many different types. Improve parallel +# compiles by breaking them up into smaller units. +vtkm_add_instantiations(array_range_instantiations + INSTANTIATIONS_FILE ArrayRangeComputeTemplate.h + ) +list(APPEND device_sources ${array_range_instantiations}) + #----------------------------------------------------------------------------- vtkm_library( NAME vtkm_cont SOURCES ${sources} From a1e8d029c552543bda69c31091a6790bdbf237d1 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Sat, 27 May 2023 15:22:49 -0600 Subject: [PATCH 27/38] Get the 3D index from a BoundaryState in WorkletPointNeighborhood There are occasions when you need a worklet to opeate on 2D or 3D indices. Most worklets operate on 1D indices, which requires recomputing the 3D index in each worklet instance. A workaround is to use a worklet that does a 3D scheduling and pull the working index from that. The problem was that there was no easy way to get this 3D index. To provide this option, a feature was added to the `BoundaryState` class that can be provided by `WorkletPointNeighborhood`. Thus, to get a 3D index in a worklet, use the `WorkletPointNeighborhood`, add `Boundary` as an argument to the `ExecutionSignature`, and then call `GetCenterIndex` on the `BoundaryState` object passed to the worklet operator. --- docs/changelog/index-from-boundary-state.md | 15 ++++ vtkm/exec/BoundaryState.h | 5 ++ .../UnitTestWorkletMapPointNeighborhood.cxx | 72 ++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/index-from-boundary-state.md diff --git a/docs/changelog/index-from-boundary-state.md b/docs/changelog/index-from-boundary-state.md new file mode 100644 index 000000000..ac3ee116e --- /dev/null +++ b/docs/changelog/index-from-boundary-state.md @@ -0,0 +1,15 @@ +# Get the 3D index from a BoundaryState in WorkletPointNeighborhood + +There are occasions when you need a worklet to opeate on 2D or 3D indices. +Most worklets operate on 1D indices, which requires recomputing the 3D +index in each worklet instance. A workaround is to use a worklet that does +a 3D scheduling and pull the working index from that. + +The problem was that there was no easy way to get this 3D index. To provide +this option, a feature was added to the `BoundaryState` class that can be +provided by `WorkletPointNeighborhood`. + +Thus, to get a 3D index in a worklet, use the `WorkletPointNeighborhood`, +add `Boundary` as an argument to the `ExecutionSignature`, and then call +`GetCenterIndex` on the `BoundaryState` object passed to the worklet +operator. diff --git a/vtkm/exec/BoundaryState.h b/vtkm/exec/BoundaryState.h index ebe2a50ce..27cbe037e 100644 --- a/vtkm/exec/BoundaryState.h +++ b/vtkm/exec/BoundaryState.h @@ -37,6 +37,11 @@ struct BoundaryState { } + /// Returns the center index of the neighborhood. This is typically the position of the + /// invocation of the worklet given this boundary condition. + /// + VTKM_EXEC const vtkm::Id3& GetCenterIndex() const { return this->IJK; } + ///@{ /// Returns true if a neighborhood of the given radius is contained within the bounds of the cell /// set in the X, Y, or Z direction. Returns false if the neighborhood extends outside of the diff --git a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx index b74aa9f84..c7ad22d99 100644 --- a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx +++ b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx @@ -17,8 +17,11 @@ #include #include +#include +#include #include #include +#include #include #include @@ -178,7 +181,34 @@ struct ScatterUniformNeighbor : public vtkm::worklet::WorkletPointNeighborhood using ScatterType = vtkm::worklet::ScatterUniform<3>; }; -} + +// An example of using WorkletPointNeighborhood to iterate over a structured 3D cell +// domain rather than look at an actual neighborhood. It reduces a domain by subsampling +// every other item in the input field. +struct Subsample : public vtkm::worklet::WorkletPointNeighborhood +{ + using ControlSignature = + void(WholeCellSetIn inputTopology, + WholeArrayIn inputField, + CellSetIn outputTopology, + FieldOut sampledField); + using ExecutionSignature = void(_1, _2, Boundary, _4); + using InputDomain = _3; + + template + VTKM_EXEC void operator()(const vtkm::exec::ConnectivityStructured& inputTopology, + const InFieldPortal& inFieldPortal, + const vtkm::exec::BoundaryState& boundary, + T& sample) const + { + sample = + inFieldPortal.Get(inputTopology.LogicalToFlatVisitIndex(2 * boundary.GetCenterIndex())); + } +}; + +} // namespace test_pointneighborhood namespace { @@ -186,6 +216,7 @@ namespace static void TestMaxNeighborValue(); static void TestScatterIdentityNeighbor(); static void TestScatterUnfiormNeighbor(); +static void TestIndexing(); void TestWorkletPointNeighborhood(vtkm::cont::DeviceAdapterId id) { @@ -195,6 +226,7 @@ void TestWorkletPointNeighborhood(vtkm::cont::DeviceAdapterId id) TestMaxNeighborValue(); TestScatterIdentityNeighbor(); TestScatterUnfiormNeighbor(); + TestIndexing(); } static void TestMaxNeighborValue() @@ -276,6 +308,44 @@ static void TestScatterUnfiormNeighbor() dispatcher.Invoke(dataSet2D.GetCellSet(), dataSet2D.GetCoordinateSystem()); } +static void TestIndexing() +{ + std::cout << "Testing using PointNeighborhood for 3D indexing." << std::endl; + + constexpr vtkm::Id outDim = 4; + constexpr vtkm::Id inDim = outDim * 2; + + vtkm::cont::CellSetStructured<3> inCellSet; + inCellSet.SetPointDimensions({ inDim }); + vtkm::cont::CellSetStructured<3> outCellSet; + outCellSet.SetPointDimensions({ outDim }); + + vtkm::cont::ArrayHandleUniformPointCoordinates inField{ { inDim } }; + + vtkm::cont::ArrayHandle outField; + + vtkm::cont::Invoker invoke; + invoke(::test_pointneighborhood::Subsample{}, inCellSet, inField, outCellSet, outField); + + VTKM_TEST_ASSERT(outField.GetNumberOfValues() == (outDim * outDim * outDim)); + + vtkm::Id flatIndex = 0; + vtkm::Id3 IJK; + auto outFieldPortal = outField.WritePortal(); + for (IJK[2] = 0; IJK[2] < outDim; ++IJK[2]) + { + for (IJK[1] = 0; IJK[1] < outDim; ++IJK[1]) + { + for (IJK[0] = 0; IJK[0] < outDim; ++IJK[0]) + { + vtkm::Vec3f computed = outFieldPortal.Get(flatIndex); + VTKM_TEST_ASSERT(test_equal(computed, 2 * IJK)); + ++flatIndex; + } + } + } +} + } // anonymous namespace int UnitTestWorkletMapPointNeighborhood(int argc, char* argv[]) From d907d832a3e274872fddc2e82b2ee9853b99683c Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Mon, 19 Jun 2023 14:27:45 -0400 Subject: [PATCH 28/38] CI,opensuse: added sles build with gcc13 --- .gitlab-ci.yml | 6 +++++ .gitlab/ci/docker/opensuse/Dockerfile | 24 +++++++++++++++++++ .gitlab/ci/opensuse.yml | 32 ++++++++++++++++++++++++++ .gitlab/ci/ubuntu2004.yml | 33 --------------------------- 4 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 .gitlab/ci/docker/opensuse/Dockerfile create mode 100644 .gitlab/ci/opensuse.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 09df394e4..1589614f3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -62,6 +62,11 @@ extends: - .docker_image +.opensuse: &opensuse + image: "kitware/vtkm:ci-opensuse-20230619" + extends: + - .docker_image + .run_automatically: &run_automatically rules: - if: '$CI_MERGE_REQUEST_ID' @@ -226,6 +231,7 @@ include: - local: '/.gitlab/ci/centos8.yml' - local: '/.gitlab/ci/doxygen.yml' - local: '/.gitlab/ci/macos.yml' + - local: '/.gitlab/ci/opensuse.yml' - local: '/.gitlab/ci/rhel8.yml' - local: '/.gitlab/ci/ubuntu1604.yml' - local: '/.gitlab/ci/ubuntu1804.yml' diff --git a/.gitlab/ci/docker/opensuse/Dockerfile b/.gitlab/ci/docker/opensuse/Dockerfile new file mode 100644 index 000000000..be11c9404 --- /dev/null +++ b/.gitlab/ci/docker/opensuse/Dockerfile @@ -0,0 +1,24 @@ +FROM opensuse/tumbleweed +LABEL maintainer "Vicente Adolfo Bolea Sanchez" + +# Base dependencies for building VTK-m projects +RUN zypper refresh && \ + zypper update -y && \ + zypper install -y --no-recommends \ + cmake \ + curl \ + gcc13-c++ \ + git \ + git-lfs \ + hdf5-devel \ + libgomp1 \ + mpich \ + mpich-devel \ + ninja \ + python311 \ + python311-scipy \ + tbb-devel && \ + zypper clean --all + +# Need to run git-lfs install manually on system packaged version +RUN git-lfs install diff --git a/.gitlab/ci/opensuse.yml b/.gitlab/ci/opensuse.yml new file mode 100644 index 000000000..8bda47f3e --- /dev/null +++ b/.gitlab/ci/opensuse.yml @@ -0,0 +1,32 @@ +build:opensuse_gcc13: + tags: + - build + - vtkm + - docker + - linux-x86_64 + extends: + - .opensuse + - .cmake_build_linux + - .run_automatically + variables: + CMAKE_BUILD_TYPE: Debug + VTKM_SETTINGS: "benchmarks+tbb+openmp+mpi+shared+hdf5+min_build" + +test:opensuse_gcc13: + tags: + - test + - vtkm + - docker + - linux-x86_64 + extends: + - .opensuse + - .cmake_test_linux + - .run_automatically + variables: + #Restrict OpenMP number of threads since multiple test stages + #execute on the same hardware concurrently + OMP_NUM_THREADS: 4 + dependencies: + - build:opensuse_gcc13 + needs: + - build:opensuse_gcc13 diff --git a/.gitlab/ci/ubuntu2004.yml b/.gitlab/ci/ubuntu2004.yml index ef0534144..d9ffbefc5 100644 --- a/.gitlab/ci/ubuntu2004.yml +++ b/.gitlab/ci/ubuntu2004.yml @@ -1,36 +1,3 @@ -build:ubuntu2004_gcc9: - tags: - - build - - vtkm - - docker - - linux-x86_64 - extends: - - .ubuntu2004 - - .cmake_build_linux - - .run_automatically - variables: - CMAKE_BUILD_TYPE: Debug - VTKM_SETTINGS: "benchmarks+tbb+openmp+mpi+shared+hdf5+min_build" - -test:ubuntu2004_gcc9: - tags: - - test - - vtkm - - docker - - linux-x86_64 - extends: - - .ubuntu2004 - - .cmake_test_linux - - .run_automatically - variables: - #Restrict OpenMP number of threads since multiple test stages - #execute on the same hardware concurrently - OMP_NUM_THREADS: 4 - dependencies: - - build:ubuntu2004_gcc9 - needs: - - build:ubuntu2004_gcc9 - build:ubuntu2004_kokkos: tags: - build From 9c0b16414bd45e93331bb414f6c3d3535eee7aec Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Mon, 19 Jun 2023 19:28:01 -0400 Subject: [PATCH 29/38] remove gcc13 warning --- .../testing/UnitTestShrinkFilter.cxx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx b/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx index ff88c443d..c9c015292 100644 --- a/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx +++ b/vtkm/filter/geometry_refinement/testing/UnitTestShrinkFilter.cxx @@ -78,15 +78,17 @@ void TestWithExplicitData() "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"); + 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(); From 1bea838be9c67e7374d4ff1a5490fd54abc62751 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Thu, 15 Jun 2023 11:58:27 -0400 Subject: [PATCH 30/38] diy: set diy version to latest for/vtk-m --- vtkm/thirdparty/diy/update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtkm/thirdparty/diy/update.sh b/vtkm/thirdparty/diy/update.sh index 5d7706f72..a6fdcf8b3 100755 --- a/vtkm/thirdparty/diy/update.sh +++ b/vtkm/thirdparty/diy/update.sh @@ -8,7 +8,7 @@ readonly name="diy" readonly ownership="Diy Upstream " readonly subtree="vtkm/thirdparty/$name/vtkm$name" readonly repo="https://gitlab.kitware.com/third-party/diy2.git" -readonly tag="for/vtk-m-20230328-g9bea15a1" +readonly tag="for/vtk-m-20230616-g40ea01f9" readonly paths=" cmake include From 12b45d864be5661e30e0f166213638632a05597d Mon Sep 17 00:00:00 2001 From: Diy Upstream Date: Fri, 16 Jun 2023 17:52:26 -0400 Subject: [PATCH 31/38] diy 2023-06-16 (3ee23f39) Code extracted from: https://gitlab.kitware.com/third-party/diy2.git at commit 3ee23f39193a00e4b601b65bb970d0631eec1662 (for/vtk-m-20230616-g40ea01f9). --- CMakeLists.txt | 24 +++++++++++++++++------- include/vtkmdiy/mpi/no-mpi.hpp | 2 +- include/vtkmdiy/serialization.hpp | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c02928b3f..344398ea9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,12 @@ endif() if (NOT DEFINED diy_export_name) set(diy_export_name "diy_targets") endif() +if (NOT DEFINED diy_development_component) + set(diy_development_component "development") +endif() +if (NOT DEFINED diy_runtime_component) + set(diy_runtime_component "runtime") +endif() if (NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY) set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") @@ -273,22 +279,26 @@ configure_package_config_file( # install targets if (NOT DEFINED diy_install_only_libraries) # defined by parent project if building for binary distribution - install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/${diy_prefix} DESTINATION ${diy_install_include_dir}) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/${diy_prefix} + DESTINATION ${diy_install_include_dir} + COMPONENT ${diy_development_component}) if (build_diy_mpi_lib) - install(FILES ${PROJECT_BINARY_DIR}/include/${diy_prefix}/mpi/mpitypes.hpp DESTINATION ${diy_install_include_dir}/${diy_prefix}/mpi) + install(FILES ${PROJECT_BINARY_DIR}/include/${diy_prefix}/mpi/mpitypes.hpp + DESTINATION ${diy_install_include_dir}/${diy_prefix}/mpi + COMPONENT ${diy_development_component}) endif() endif() install(TARGETS ${diy_targets} EXPORT ${diy_export_name} - ARCHIVE DESTINATION ${diy_install_lib_dir} - LIBRARY DESTINATION ${diy_install_lib_dir} - RUNTIME DESTINATION ${diy_install_bin_dir}) + ARCHIVE DESTINATION ${diy_install_lib_dir} COMPONENT ${diy_development_component} + LIBRARY DESTINATION ${diy_install_lib_dir} COMPONENT ${diy_runtime_component} + RUNTIME DESTINATION ${diy_install_bin_dir} COMPONENT ${diy_runtime_component}) if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) # Only generate these files when diy is the main project export(EXPORT ${diy_export_name} NAMESPACE DIY:: FILE "${PROJECT_BINARY_DIR}/diy-targets.cmake") - install(EXPORT ${diy_export_name} NAMESPACE DIY:: DESTINATION "." FILE diy-targets.cmake) - install(FILES "${PROJECT_BINARY_DIR}/diy-config.cmake" DESTINATION ".") + install(EXPORT ${diy_export_name} NAMESPACE DIY:: DESTINATION "." FILE diy-targets.cmake COMPONENT ${diy_development_component}) + install(FILES "${PROJECT_BINARY_DIR}/diy-config.cmake" DESTINATION "." COMPONENT ${diy_development_component}) endif() if (python) diff --git a/include/vtkmdiy/mpi/no-mpi.hpp b/include/vtkmdiy/mpi/no-mpi.hpp index 6809281ea..1cc5fc387 100644 --- a/include/vtkmdiy/mpi/no-mpi.hpp +++ b/include/vtkmdiy/mpi/no-mpi.hpp @@ -2,9 +2,9 @@ #define VTKMDIY_MPI_NO_MPI_HPP #include // std::assert +#include // uintptr_t #include // std::runtime_error - static const int MPI_SUCCESS = 0; static const int MPI_ANY_SOURCE = -1; static const int MPI_ANY_TAG = -1; diff --git a/include/vtkmdiy/serialization.hpp b/include/vtkmdiy/serialization.hpp index 0492fc32a..368fc0639 100644 --- a/include/vtkmdiy/serialization.hpp +++ b/include/vtkmdiy/serialization.hpp @@ -69,7 +69,7 @@ namespace diy void wipe() { std::vector().swap(buffer); reset(); } void reset() { position = 0; } void skip(size_t s) { position += s; } - void swap(MemoryBuffer& o) { std::swap(position, o.position); buffer.swap(o.buffer); } + void swap(MemoryBuffer& o) { std::swap(position, o.position); buffer.swap(o.buffer); std::swap(blob_position, o.blob_position); blobs.swap(o.blobs); } bool empty() const { return buffer.empty(); } size_t size() const { return buffer.size(); } void reserve(size_t s) { buffer.reserve(s); } From fc9077e0c5017a9fcda0ef6531af0c2ac9784d4a Mon Sep 17 00:00:00 2001 From: Sujin Philip Date: Mon, 5 Jun 2023 09:21:12 -0400 Subject: [PATCH 32/38] Mark ArrayHandle constructors taking buffers, as explicit This resolves a compiler ambiguity I hit during development. In my case, I created an `ArrayHandleDecorator` with one of the arrays being an `ArrayHandleTransform`. The ambiguity occurs in function `DecoratorStorageTraits<...>::BuffersToArray`, here an `ArrayHandleTransform` is constructed using buffers (`std::vector`) This constructor is not defined for `ArrayHandleTransform`, but it's defined for its superclass (`vtkm::cont::ArrayHandle`). `ArrayHandleTransform` does have a non-explicit constructor that takes the array to be transformed and the transform-functor as parameters, where the later has a default value. This produces the following ambiguous options for the compiler: 1. Create a "to-be-transformed" ArrayHandle instance using the buffers, call the `ArrayHandleTransform` constructor with this array with the defaulted functor parameter. 2. Create the superclass instance using the buffer and call the `ArrayHandleTransform` constructor that takes the superclass. In this situation, option 2 is the correct choice. The ambiguity is resolved by marking the constructors that take buffers as explicit. These constructors are also added for the derived classess via the `VTK_M_ARRAY_HANDLE_SUBCLASS_IMPL` macro. --- vtkm/cont/ArrayHandle.h | 16 ++++++++++++++-- vtkm/cont/ArrayHandleZip.h | 4 ++-- .../UnitTestWorkletMapPointNeighborhood.cxx | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/vtkm/cont/ArrayHandle.h b/vtkm/cont/ArrayHandle.h index 8c149a440..8920ce642 100644 --- a/vtkm/cont/ArrayHandle.h +++ b/vtkm/cont/ArrayHandle.h @@ -186,6 +186,18 @@ struct GetTypeInParentheses } \ \ VTKM_CONT \ + explicit classname(const std::vector& buffers) \ + : Superclass(buffers) \ + { \ + } \ + \ + VTKM_CONT \ + explicit classname(std::vector&& buffers) noexcept \ + : Superclass(std::move(buffers)) \ + { \ + } \ + \ + VTKM_CONT \ Thisclass& operator=(const Thisclass& src) \ { \ this->Superclass::operator=(src); \ @@ -332,12 +344,12 @@ public: /// Special constructor for subclass specializations that need to set the /// initial state array. Used when pulling data from other sources. /// - VTKM_CONT ArrayHandle(const std::vector& buffers) + VTKM_CONT explicit ArrayHandle(const std::vector& buffers) : Buffers(buffers) { } - VTKM_CONT ArrayHandle(std::vector&& buffers) noexcept + VTKM_CONT explicit ArrayHandle(std::vector&& buffers) noexcept : Buffers(std::move(buffers)) { } diff --git a/vtkm/cont/ArrayHandleZip.h b/vtkm/cont/ArrayHandleZip.h index b8a18e2fd..7d5c14f82 100644 --- a/vtkm/cont/ArrayHandleZip.h +++ b/vtkm/cont/ArrayHandleZip.h @@ -230,11 +230,11 @@ public: static FirstArrayType GetFirstArray(const std::vector& buffers) { - return { FirstArrayBuffers(buffers) }; + return FirstArrayType(FirstArrayBuffers(buffers)); } static SecondArrayType GetSecondArray(const std::vector& buffers) { - return { SecondArrayBuffers(buffers) }; + return SecondArrayType(SecondArrayBuffers(buffers)); } }; } // namespace internal diff --git a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx index c7ad22d99..99231f688 100644 --- a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx +++ b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx @@ -320,7 +320,7 @@ static void TestIndexing() vtkm::cont::CellSetStructured<3> outCellSet; outCellSet.SetPointDimensions({ outDim }); - vtkm::cont::ArrayHandleUniformPointCoordinates inField{ { inDim } }; + vtkm::cont::ArrayHandleUniformPointCoordinates inField(vtkm::Id3{ inDim }); vtkm::cont::ArrayHandle outField; From e013ad126fd4e3831b2a972ffb41b09268863a51 Mon Sep 17 00:00:00 2001 From: "Gunther H. Weber" Date: Thu, 2 Mar 2023 19:42:08 -0800 Subject: [PATCH 33/38] Add test for GlobalPointIndexStart to TestingExtractStructured --- .../testing/UnitTestExtractStructuredFilter.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx index 92ac31e72..99f0eb5af 100644 --- a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx +++ b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx @@ -26,6 +26,13 @@ public: std::cout << "Testing extract structured uniform" << std::endl; vtkm::cont::DataSet dataset = MakeTestDataSet().Make2DUniformDataSet1(); + // Change point index start from 0, 0 to 10, 14 + vtkm::cont::CellSetStructured<2> cellSet; + dataset.GetCellSet().AsCellSet(cellSet); + cellSet.SetGlobalPointIndexStart(vtkm::Id2{ 10, 14 }); + dataset.SetCellSet(cellSet); + dataset.PrintSummary(std::cout); + vtkm::RangeId3 range(1, 4, 1, 4, 0, 1); vtkm::Id3 sample(1, 1, 1); @@ -35,10 +42,17 @@ public: extract.SetFieldsToPass({ "pointvar", "cellvar" }); vtkm::cont::DataSet output = extract.Execute(dataset); + output.PrintSummary(std::cout); VTKM_TEST_ASSERT(test_equal(output.GetCellSet().GetNumberOfPoints(), 9), "Wrong result for ExtractStructured worklet"); VTKM_TEST_ASSERT(test_equal(output.GetNumberOfCells(), 4), "Wrong result for ExtractStructured worklet"); + vtkm::cont::CellSetStructured<2> outputCellSet; + output.GetCellSet().AsCellSet(outputCellSet); + VTKM_TEST_ASSERT(test_equal(outputCellSet.GetGlobalPointIndexStart()[0], 11), + "Wrong result for ExtractStructured PointIndexStart"); + VTKM_TEST_ASSERT(test_equal(outputCellSet.GetGlobalPointIndexStart()[1], 15), + "Wrong result for ExtractStructured PointIndexStart"); vtkm::cont::ArrayHandle outPointData; output.GetField("pointvar").GetData().AsArrayHandle(outPointData); From e55b700f7576fce819a3ac2e7da6e5d22b605e39 Mon Sep 17 00:00:00 2001 From: "Gunther H. Weber" Date: Tue, 7 Mar 2023 20:42:24 -0800 Subject: [PATCH 34/38] Deprecate SetIncludeOffset and rename to SetVOIIsGlobal --- vtkm/filter/entity_extraction/ExtractStructured.cxx | 2 +- vtkm/filter/entity_extraction/ExtractStructured.h | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/vtkm/filter/entity_extraction/ExtractStructured.cxx b/vtkm/filter/entity_extraction/ExtractStructured.cxx index a1962fb51..891a115b0 100644 --- a/vtkm/filter/entity_extraction/ExtractStructured.cxx +++ b/vtkm/filter/entity_extraction/ExtractStructured.cxx @@ -74,7 +74,7 @@ vtkm::cont::DataSet ExtractStructured::DoExecute(const vtkm::cont::DataSet& inpu this->VOI, this->SampleRate, this->IncludeBoundary, - this->IncludeOffset); + this->VOIIsGlobal); // Create map arrays for mapping fields. Could potentially save some time to first check to see // if these arrays would be used. diff --git a/vtkm/filter/entity_extraction/ExtractStructured.h b/vtkm/filter/entity_extraction/ExtractStructured.h index b4f1599d2..b1eb20e52 100644 --- a/vtkm/filter/entity_extraction/ExtractStructured.h +++ b/vtkm/filter/entity_extraction/ExtractStructured.h @@ -78,8 +78,17 @@ public: VTKM_CONT void SetIncludeBoundary(bool value) { this->IncludeBoundary = value; } + /// Get if VOI is specified in global point (rather than in local) indices VTKM_CONT - void SetIncludeOffset(bool value) { this->IncludeOffset = value; } + bool GetVOIIsGlobal() const { return this->VOIIsGlobal; } + /// Set if VOI is specified in global point (rather than in local) indices + VTKM_CONT + void SetVOIIsGlobal(bool value) { this->VOIIsGlobal = value; } + /// Set if VOI is specified in global point (rather than in local) indices + /// (depracted in favor of a method with a name that better conveys purpose) + VTKM_DEPRECATED(2.0) + VTKM_CONT + void SetIncludeOffset(bool value) { this->VOIIsGlobal = value; } private: VTKM_CONT @@ -88,7 +97,7 @@ private: vtkm::RangeId3 VOI = vtkm::RangeId3(0, -1, 0, -1, 0, -1); vtkm::Id3 SampleRate = { 1, 1, 1 }; bool IncludeBoundary = false; - bool IncludeOffset = false; + bool VOIIsGlobal = false; }; } // namespace entity_extraction From 84e719ae17e3992fe0fa0f45e2df5cb38dbff0c1 Mon Sep 17 00:00:00 2001 From: "Gunther H. Weber" Date: Tue, 7 Mar 2023 20:44:11 -0800 Subject: [PATCH 35/38] Set GlobalPointIndexStart correctly, copy GlobalPointDimensions --- .../worklet/ExtractStructured.h | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/vtkm/filter/entity_extraction/worklet/ExtractStructured.h b/vtkm/filter/entity_extraction/worklet/ExtractStructured.h index f312422cd..3013bdc8b 100644 --- a/vtkm/filter/entity_extraction/worklet/ExtractStructured.h +++ b/vtkm/filter/entity_extraction/worklet/ExtractStructured.h @@ -136,6 +136,7 @@ private: static UncertainCellSetStructured MakeCellSetStructured( const vtkm::Id3& inputPointDims, const vtkm::Id3& inputOffsets, + const vtkm::Id3& inputGlobalPointDims, vtkm::IdComponent forcedDimensionality = 0) { // when the point dimension for a given axis is 1 we @@ -146,12 +147,22 @@ private: vtkm::IdComponent dimensionality = forcedDimensionality; vtkm::Id3 dimensions = inputPointDims; vtkm::Id3 offset = inputOffsets; + vtkm::Id3 globalDimensions = inputGlobalPointDims; for (int i = 0; i < 3 && (forcedDimensionality == 0); ++i) { if (inputPointDims[i] > 1) { dimensions[dimensionality] = inputPointDims[i]; offset[dimensionality] = inputOffsets[i]; + // TODO/FIXME: This may not be the correct way to handle global point dims. + // E.g., if we preserve the input global point dims (default) then they may + // have a higher dimensionility than the returned data set. In that case, + // the approach here will result in an incorrect value for GlobalPointDimensions. + // This is the simplest approach, which should work in most use cases for this + // filter, but if this choice causes further problems down the way, we may need + // to rethink it. + globalDimensions[dimensionality] = inputGlobalPointDims[i]; + ++dimensionality; } } @@ -163,6 +174,7 @@ private: vtkm::cont::CellSetStructured<1> outCs; outCs.SetPointDimensions(dimensions[0]); outCs.SetGlobalPointIndexStart(offset[0]); + outCs.SetGlobalPointDimensions(globalDimensions[0]); return outCs; } case 2: @@ -170,6 +182,7 @@ private: vtkm::cont::CellSetStructured<2> outCs; outCs.SetPointDimensions(vtkm::Id2(dimensions[0], dimensions[1])); outCs.SetGlobalPointIndexStart(vtkm::Id2(offset[0], offset[1])); + outCs.SetGlobalPointDimensions(vtkm::Id2(globalDimensions[0], globalDimensions[1])); return outCs; } case 3: @@ -177,6 +190,7 @@ private: vtkm::cont::CellSetStructured<3> outCs; outCs.SetPointDimensions(dimensions); outCs.SetGlobalPointIndexStart(offset); + outCs.SetGlobalPointDimensions(globalDimensions); return outCs; } default: @@ -189,58 +203,65 @@ public: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset) + bool voiIsGlobal) { vtkm::Id pdims = cellset.GetPointDimensions(); vtkm::Id offsets = cellset.GetGlobalPointIndexStart(); + vtkm::Id gpdims = cellset.GetGlobalPointDimensions(); return this->Compute(1, vtkm::Id3{ pdims, 1, 1 }, vtkm::Id3{ offsets, 0, 0 }, + vtkm::Id3{ gpdims, 1, 1 }, voi, sampleRate, includeBoundary, - includeOffset); + voiIsGlobal); } inline UncertainCellSetStructured Run(const vtkm::cont::CellSetStructured<2>& cellset, const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset) + bool voiIsGlobal) { vtkm::Id2 pdims = cellset.GetPointDimensions(); vtkm::Id2 offsets = cellset.GetGlobalPointIndexStart(); + vtkm::Id2 gpdims = cellset.GetGlobalPointDimensions(); return this->Compute(2, vtkm::Id3{ pdims[0], pdims[1], 1 }, vtkm::Id3{ offsets[0], offsets[1], 0 }, + vtkm::Id3{ gpdims[0], gpdims[1], 1 }, voi, sampleRate, includeBoundary, - includeOffset); + voiIsGlobal); } inline UncertainCellSetStructured Run(const vtkm::cont::CellSetStructured<3>& cellset, const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset) + bool voiIsGlobal) { vtkm::Id3 pdims = cellset.GetPointDimensions(); vtkm::Id3 offsets = cellset.GetGlobalPointIndexStart(); - return this->Compute(3, pdims, offsets, voi, sampleRate, includeBoundary, includeOffset); + vtkm::Id3 gpdims = cellset.GetGlobalPointDimensions(); + return this->Compute(3, pdims, offsets, gpdims, voi, sampleRate, includeBoundary, voiIsGlobal); } UncertainCellSetStructured Compute(const int dimensionality, const vtkm::Id3& ptdim, const vtkm::Id3& offsets, + const vtkm::Id3& gpdims, const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset) + bool voiIsGlobal) { // Verify input parameters vtkm::Id3 offset_vec(0, 0, 0); vtkm::Id3 globalOffset(0, 0, 0); + vtkm::Id3 globalPointDimensions = gpdims; this->InputDimensions = ptdim; this->InputDimensionality = dimensionality; @@ -250,7 +271,7 @@ public: { throw vtkm::cont::ErrorBadValue("Bad sampling rate"); } - if (includeOffset) + if (voiIsGlobal) { vtkm::Id3 tmpDims = ptdim; offset_vec = offsets; @@ -315,9 +336,9 @@ public: if (!this->VOI.IsNonEmpty()) { vtkm::Id3 empty = { 0, 0, 0 }; - return MakeCellSetStructured(empty, empty, dimensionality); + return MakeCellSetStructured(empty, empty, globalPointDimensions, dimensionality); } - if (!includeOffset) + if (!voiIsGlobal) { // compute output dimensions this->OutputDimensions = vtkm::Id3(1, 1, 1); @@ -354,9 +375,15 @@ public: MakeAxisIndexArrayCells(vtkm::Max(vtkm::Id(1), this->OutputDimensions[2] - 1), this->VOI.Z.Min, this->SampleRate[2])); + + // compute global point origin + for (int i = 0; i < dimensionality; ++i) + { + globalOffset[i] = offsets[i] + this->VOI[i].Min; + } } - return MakeCellSetStructured(this->OutputDimensions, globalOffset); + return MakeCellSetStructured(this->OutputDimensions, globalOffset, globalPointDimensions); } @@ -368,13 +395,13 @@ private: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset, + bool voiIsGlobal, UncertainCellSetStructured& output) : Worklet(worklet) , VOI(&voi) , SampleRate(&sampleRate) , IncludeBoundary(includeBoundary) - , IncludeOffset(includeOffset) + , VOIIsGlobal(voiIsGlobal) , Output(&output) { } @@ -383,7 +410,7 @@ private: void operator()(const vtkm::cont::CellSetStructured& cellset) const { *this->Output = this->Worklet->Run( - cellset, *this->VOI, *this->SampleRate, this->IncludeBoundary, this->IncludeOffset); + cellset, *this->VOI, *this->SampleRate, this->IncludeBoundary, this->VOIIsGlobal); } template @@ -397,7 +424,7 @@ private: const vtkm::RangeId3* VOI; const vtkm::Id3* SampleRate; bool IncludeBoundary; - bool IncludeOffset; + bool VOIIsGlobal; UncertainCellSetStructured* Output; }; @@ -407,10 +434,10 @@ public: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool includeOffset) + bool voiIsGlobal) { UncertainCellSetStructured output; - CallRun cr(this, voi, sampleRate, includeBoundary, includeOffset, output); + CallRun cr(this, voi, sampleRate, includeBoundary, voiIsGlobal, output); vtkm::cont::CastAndCall(cellset, cr); return output; } From 523c8f3f21eb07c40d948e21d55c36d1ccd5ee77 Mon Sep 17 00:00:00 2001 From: "Gunther H. Weber" Date: Tue, 7 Mar 2023 20:44:43 -0800 Subject: [PATCH 36/38] Add test whether GlobalPointDimensions are preserved --- .../testing/UnitTestExtractStructuredFilter.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx index 99f0eb5af..27c10945f 100644 --- a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx +++ b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx @@ -29,7 +29,9 @@ public: // Change point index start from 0, 0 to 10, 14 vtkm::cont::CellSetStructured<2> cellSet; dataset.GetCellSet().AsCellSet(cellSet); + cellSet.SetGlobalPointDimensions(vtkm::Id2{ 15, 19 }); cellSet.SetGlobalPointIndexStart(vtkm::Id2{ 10, 14 }); + //cellSet.SetGlobalPointIndexStart(vtkm::Id2{ 0, 0 }); dataset.SetCellSet(cellSet); dataset.PrintSummary(std::cout); @@ -39,6 +41,7 @@ public: vtkm::filter::entity_extraction::ExtractStructured extract; extract.SetVOI(range); extract.SetSampleRate(sample); + //extract.SetVOIIsGlobal(true); extract.SetFieldsToPass({ "pointvar", "cellvar" }); vtkm::cont::DataSet output = extract.Execute(dataset); @@ -53,6 +56,11 @@ public: "Wrong result for ExtractStructured PointIndexStart"); VTKM_TEST_ASSERT(test_equal(outputCellSet.GetGlobalPointIndexStart()[1], 15), "Wrong result for ExtractStructured PointIndexStart"); + VTKM_TEST_ASSERT(test_equal(outputCellSet.GetGlobalPointDimensions()[0], 15), + "Wrong result for ExtractStructured GlobalPointDimensions"); + VTKM_TEST_ASSERT(test_equal(outputCellSet.GetGlobalPointDimensions()[1], 19), + "Wrong result for ExtractStructured GlobalPointDimensions"); + vtkm::cont::ArrayHandle outPointData; output.GetField("pointvar").GetData().AsArrayHandle(outPointData); From 7bea5413cf6643f2c18f01566a0f7157cd251af7 Mon Sep 17 00:00:00 2001 From: "Gunther H. Weber" Date: Thu, 9 Mar 2023 13:20:07 -0800 Subject: [PATCH 37/38] Revert from VOIIsGlobal to IncludeOffset. Add comment about deprecation reasoning. --- .../entity_extraction/ExtractStructured.cxx | 2 +- .../entity_extraction/ExtractStructured.h | 21 ++++++------- .../worklet/ExtractStructured.h | 31 ++++++++++--------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/vtkm/filter/entity_extraction/ExtractStructured.cxx b/vtkm/filter/entity_extraction/ExtractStructured.cxx index 891a115b0..a1962fb51 100644 --- a/vtkm/filter/entity_extraction/ExtractStructured.cxx +++ b/vtkm/filter/entity_extraction/ExtractStructured.cxx @@ -74,7 +74,7 @@ vtkm::cont::DataSet ExtractStructured::DoExecute(const vtkm::cont::DataSet& inpu this->VOI, this->SampleRate, this->IncludeBoundary, - this->VOIIsGlobal); + this->IncludeOffset); // Create map arrays for mapping fields. Could potentially save some time to first check to see // if these arrays would be used. diff --git a/vtkm/filter/entity_extraction/ExtractStructured.h b/vtkm/filter/entity_extraction/ExtractStructured.h index b1eb20e52..1d01bb160 100644 --- a/vtkm/filter/entity_extraction/ExtractStructured.h +++ b/vtkm/filter/entity_extraction/ExtractStructured.h @@ -78,17 +78,16 @@ public: VTKM_CONT void SetIncludeBoundary(bool value) { this->IncludeBoundary = value; } - /// Get if VOI is specified in global point (rather than in local) indices + /// Set if VOI is specified in global (rather than in local) point indices + /// (NOTE: Depracted this method since this does not seem to work as + /// expected and there are no tests for it. Furthermore, neither VTK-m nor + /// VTK-h/Ascent seem to use this method. If your are using this method + /// somewhere else and think it should remain, please open a merge request to + /// "de-deprecate" it and add a test and documentation of the expected + /// behavior.) + VTKM_DEPRECATED(2.1) VTKM_CONT - bool GetVOIIsGlobal() const { return this->VOIIsGlobal; } - /// Set if VOI is specified in global point (rather than in local) indices - VTKM_CONT - void SetVOIIsGlobal(bool value) { this->VOIIsGlobal = value; } - /// Set if VOI is specified in global point (rather than in local) indices - /// (depracted in favor of a method with a name that better conveys purpose) - VTKM_DEPRECATED(2.0) - VTKM_CONT - void SetIncludeOffset(bool value) { this->VOIIsGlobal = value; } + void SetIncludeOffset(bool value) { this->IncludeOffset = value; } private: VTKM_CONT @@ -97,7 +96,7 @@ private: vtkm::RangeId3 VOI = vtkm::RangeId3(0, -1, 0, -1, 0, -1); vtkm::Id3 SampleRate = { 1, 1, 1 }; bool IncludeBoundary = false; - bool VOIIsGlobal = false; + bool IncludeOffset = false; }; } // namespace entity_extraction diff --git a/vtkm/filter/entity_extraction/worklet/ExtractStructured.h b/vtkm/filter/entity_extraction/worklet/ExtractStructured.h index 3013bdc8b..c1a97f2f1 100644 --- a/vtkm/filter/entity_extraction/worklet/ExtractStructured.h +++ b/vtkm/filter/entity_extraction/worklet/ExtractStructured.h @@ -203,7 +203,7 @@ public: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal) + bool includeOffset) { vtkm::Id pdims = cellset.GetPointDimensions(); vtkm::Id offsets = cellset.GetGlobalPointIndexStart(); @@ -215,14 +215,14 @@ public: voi, sampleRate, includeBoundary, - voiIsGlobal); + includeOffset); } inline UncertainCellSetStructured Run(const vtkm::cont::CellSetStructured<2>& cellset, const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal) + bool includeOffset) { vtkm::Id2 pdims = cellset.GetPointDimensions(); vtkm::Id2 offsets = cellset.GetGlobalPointIndexStart(); @@ -234,19 +234,20 @@ public: voi, sampleRate, includeBoundary, - voiIsGlobal); + includeOffset); } inline UncertainCellSetStructured Run(const vtkm::cont::CellSetStructured<3>& cellset, const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal) + bool includeOffset) { vtkm::Id3 pdims = cellset.GetPointDimensions(); vtkm::Id3 offsets = cellset.GetGlobalPointIndexStart(); vtkm::Id3 gpdims = cellset.GetGlobalPointDimensions(); - return this->Compute(3, pdims, offsets, gpdims, voi, sampleRate, includeBoundary, voiIsGlobal); + return this->Compute( + 3, pdims, offsets, gpdims, voi, sampleRate, includeBoundary, includeOffset); } UncertainCellSetStructured Compute(const int dimensionality, @@ -256,7 +257,7 @@ public: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal) + bool includeOffset) { // Verify input parameters vtkm::Id3 offset_vec(0, 0, 0); @@ -271,7 +272,7 @@ public: { throw vtkm::cont::ErrorBadValue("Bad sampling rate"); } - if (voiIsGlobal) + if (includeOffset) { vtkm::Id3 tmpDims = ptdim; offset_vec = offsets; @@ -338,7 +339,7 @@ public: vtkm::Id3 empty = { 0, 0, 0 }; return MakeCellSetStructured(empty, empty, globalPointDimensions, dimensionality); } - if (!voiIsGlobal) + if (!includeOffset) { // compute output dimensions this->OutputDimensions = vtkm::Id3(1, 1, 1); @@ -395,13 +396,13 @@ private: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal, + bool includeOffset, UncertainCellSetStructured& output) : Worklet(worklet) , VOI(&voi) , SampleRate(&sampleRate) , IncludeBoundary(includeBoundary) - , VOIIsGlobal(voiIsGlobal) + , IncludeOffset(includeOffset) , Output(&output) { } @@ -410,7 +411,7 @@ private: void operator()(const vtkm::cont::CellSetStructured& cellset) const { *this->Output = this->Worklet->Run( - cellset, *this->VOI, *this->SampleRate, this->IncludeBoundary, this->VOIIsGlobal); + cellset, *this->VOI, *this->SampleRate, this->IncludeBoundary, this->IncludeOffset); } template @@ -424,7 +425,7 @@ private: const vtkm::RangeId3* VOI; const vtkm::Id3* SampleRate; bool IncludeBoundary; - bool VOIIsGlobal; + bool IncludeOffset; UncertainCellSetStructured* Output; }; @@ -434,10 +435,10 @@ public: const vtkm::RangeId3& voi, const vtkm::Id3& sampleRate, bool includeBoundary, - bool voiIsGlobal) + bool includeOffset) { UncertainCellSetStructured output; - CallRun cr(this, voi, sampleRate, includeBoundary, voiIsGlobal, output); + CallRun cr(this, voi, sampleRate, includeBoundary, includeOffset, output); vtkm::cont::CastAndCall(cellset, cr); return output; } From 8f4d5fdf80ee63ddbd1b28425dbe4cdfead2e453 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 21 Jun 2023 17:33:05 -0400 Subject: [PATCH 38/38] Remove some unneeded test comments and debug code --- .../testing/UnitTestExtractStructuredFilter.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx index 27c10945f..5ce8805c9 100644 --- a/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx +++ b/vtkm/filter/entity_extraction/testing/UnitTestExtractStructuredFilter.cxx @@ -31,7 +31,6 @@ public: dataset.GetCellSet().AsCellSet(cellSet); cellSet.SetGlobalPointDimensions(vtkm::Id2{ 15, 19 }); cellSet.SetGlobalPointIndexStart(vtkm::Id2{ 10, 14 }); - //cellSet.SetGlobalPointIndexStart(vtkm::Id2{ 0, 0 }); dataset.SetCellSet(cellSet); dataset.PrintSummary(std::cout); @@ -41,11 +40,9 @@ public: vtkm::filter::entity_extraction::ExtractStructured extract; extract.SetVOI(range); extract.SetSampleRate(sample); - //extract.SetVOIIsGlobal(true); extract.SetFieldsToPass({ "pointvar", "cellvar" }); vtkm::cont::DataSet output = extract.Execute(dataset); - output.PrintSummary(std::cout); VTKM_TEST_ASSERT(test_equal(output.GetCellSet().GetNumberOfPoints(), 9), "Wrong result for ExtractStructured worklet"); VTKM_TEST_ASSERT(test_equal(output.GetNumberOfCells(), 4),