2019-04-23 22:14:56 +00:00
|
|
|
//============================================================================
|
2019-04-23 14:57:35 +00:00
|
|
|
//
|
2019-04-23 14:57:35 +00:00
|
|
|
// 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.
|
2019-04-23 14:57:35 +00:00
|
|
|
//
|
2019-04-23 22:14:56 +00:00
|
|
|
//=======================================================================
|
2019-04-23 14:57:35 +00:00
|
|
|
#ifndef vtk_m_worklet_moments_ComputeMoments_h
|
|
|
|
#define vtk_m_worklet_moments_ComputeMoments_h
|
|
|
|
|
2019-06-14 18:46:43 +00:00
|
|
|
#include <vtkm/Math.h>
|
2019-04-23 14:57:35 +00:00
|
|
|
#include <vtkm/worklet/WorkletPointNeighborhood.h>
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleRecombineVec.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
|
|
|
#include <vtkm/cont/DataSet.h>
|
2019-07-24 15:32:03 +00:00
|
|
|
#include <vtkm/cont/Field.h>
|
2022-01-04 22:38:18 +00:00
|
|
|
#include <vtkm/cont/UncertainArrayHandle.h>
|
2022-02-07 17:03:08 +00:00
|
|
|
#include <vtkm/cont/UncertainCellSet.h>
|
2019-07-24 15:32:03 +00:00
|
|
|
|
|
|
|
#include <vtkm/exec/BoundaryState.h>
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <string>
|
|
|
|
|
2019-04-23 14:57:35 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace worklet
|
|
|
|
{
|
|
|
|
namespace moments
|
|
|
|
{
|
2019-05-20 20:55:12 +00:00
|
|
|
|
|
|
|
struct ComputeMoments2D : public vtkm::worklet::WorkletPointNeighborhood
|
2019-04-23 14:57:35 +00:00
|
|
|
{
|
|
|
|
public:
|
2022-02-07 17:51:04 +00:00
|
|
|
ComputeMoments2D(const vtkm::Vec3f& _spacing, vtkm::Float64 _radius, int _p, int _q)
|
2022-02-07 18:09:59 +00:00
|
|
|
: RadiusDiscrete(vtkm::IdComponent(_radius / (_spacing[0] - 1e-10)),
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::IdComponent(_radius / (_spacing[1] - 1e-10)),
|
|
|
|
vtkm::IdComponent(_radius / (_spacing[2] - 1e-10)))
|
|
|
|
, SpacingProduct(_spacing[0] * _spacing[1])
|
2019-04-23 14:57:35 +00:00
|
|
|
, p(_p)
|
|
|
|
, q(_q)
|
|
|
|
{
|
2019-09-12 20:17:20 +00:00
|
|
|
assert(_spacing[0] > 1e-10);
|
|
|
|
assert(_spacing[1] > 1e-10);
|
|
|
|
assert(_spacing[2] > 1e-10);
|
2019-06-17 18:27:52 +00:00
|
|
|
|
2019-04-23 14:57:35 +00:00
|
|
|
assert(_p >= 0);
|
|
|
|
assert(_q >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
|
|
|
|
|
2019-07-16 20:35:53 +00:00
|
|
|
using ExecutionSignature = void(_2, Boundary, _3);
|
2019-04-23 14:57:35 +00:00
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
template <typename NeighIn, typename TOut>
|
2019-07-16 20:35:53 +00:00
|
|
|
VTKM_EXEC void operator()(const NeighIn& image,
|
|
|
|
const vtkm::exec::BoundaryState& boundary,
|
2023-05-22 19:03:23 +00:00
|
|
|
TOut& moment) const
|
2019-04-23 14:57:35 +00:00
|
|
|
{
|
2023-05-22 19:03:23 +00:00
|
|
|
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<ComponentType>::ZeroInitialization();
|
|
|
|
}
|
2019-07-16 20:35:53 +00:00
|
|
|
|
|
|
|
// Clamp the radius to the dataset bounds (discard out-of-bounds points).
|
2019-10-16 13:47:29 +00:00
|
|
|
const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete);
|
|
|
|
const auto maxRadius = boundary.ClampNeighborIndex(this->RadiusDiscrete);
|
2019-07-16 20:35:53 +00:00
|
|
|
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::Vec2f_64 radius;
|
2019-07-16 20:35:53 +00:00
|
|
|
for (vtkm::IdComponent j = minRadius[1]; j <= maxRadius[1]; ++j)
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2019-10-16 13:47:29 +00:00
|
|
|
if (j > -this->RadiusDiscrete[1] && boundary.IJK[1] + j == 0)
|
2019-07-16 20:35:53 +00:00
|
|
|
{ // Don't double count samples that exist on other nodes:
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-16 13:47:29 +00:00
|
|
|
radius[1] = j * 1. / this->RadiusDiscrete[1];
|
2019-07-16 20:35:53 +00:00
|
|
|
|
|
|
|
for (vtkm::IdComponent i = minRadius[0]; i <= maxRadius[0]; ++i)
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2019-10-16 13:47:29 +00:00
|
|
|
if (i > -this->RadiusDiscrete[0] && boundary.IJK[0] + i == 0)
|
2019-07-16 20:35:53 +00:00
|
|
|
{ // Don't double count samples that exist on other nodes:
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-16 13:47:29 +00:00
|
|
|
radius[0] = i * 1. / this->RadiusDiscrete[0];
|
2019-07-16 20:35:53 +00:00
|
|
|
|
2019-10-16 13:47:29 +00:00
|
|
|
if (vtkm::Dot(radius, radius) <= 1)
|
2019-07-16 20:35:53 +00:00
|
|
|
{
|
2023-05-22 19:03:23 +00:00
|
|
|
ComponentType multiplier =
|
|
|
|
static_cast<ComponentType>(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];
|
|
|
|
}
|
2019-07-16 20:35:53 +00:00
|
|
|
}
|
2019-05-20 20:55:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
// For variable sized Vecs, need to iterate over each component.
|
|
|
|
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
|
|
|
|
{
|
|
|
|
moment[componentI] *= static_cast<ComponentType>(this->SpacingProduct);
|
|
|
|
}
|
2019-05-20 20:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::Vec3i_32 RadiusDiscrete;
|
2022-02-07 17:51:04 +00:00
|
|
|
const vtkm::Float64 SpacingProduct;
|
2019-05-20 20:55:12 +00:00
|
|
|
const int p;
|
|
|
|
const int q;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ComputeMoments3D : public vtkm::worklet::WorkletPointNeighborhood
|
|
|
|
{
|
|
|
|
public:
|
2022-02-07 17:51:04 +00:00
|
|
|
ComputeMoments3D(const vtkm::Vec3f& _spacing, vtkm::Float64 _radius, int _p, int _q, int _r)
|
2022-02-07 18:09:59 +00:00
|
|
|
: RadiusDiscrete(vtkm::IdComponent(_radius / (_spacing[0] - 1e-10)),
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::IdComponent(_radius / (_spacing[1] - 1e-10)),
|
|
|
|
vtkm::IdComponent(_radius / (_spacing[2] - 1e-10)))
|
|
|
|
, SpacingProduct(vtkm::ReduceProduct(_spacing))
|
2019-05-20 20:55:12 +00:00
|
|
|
, p(_p)
|
|
|
|
, q(_q)
|
|
|
|
, r(_r)
|
|
|
|
{
|
2019-09-12 20:17:20 +00:00
|
|
|
assert(_spacing[0] > 1e-10);
|
|
|
|
assert(_spacing[1] > 1e-10);
|
|
|
|
assert(_spacing[2] > 1e-10);
|
2019-07-24 15:32:03 +00:00
|
|
|
|
2019-05-20 20:55:12 +00:00
|
|
|
assert(_p >= 0);
|
|
|
|
assert(_q >= 0);
|
|
|
|
assert(_r >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
using ControlSignature = void(CellSetIn, FieldInNeighborhood, FieldOut);
|
|
|
|
|
2019-07-16 20:35:53 +00:00
|
|
|
using ExecutionSignature = void(_2, Boundary, _3);
|
2019-05-20 20:55:12 +00:00
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
template <typename NeighIn, typename TOut>
|
2019-07-16 20:35:53 +00:00
|
|
|
VTKM_EXEC void operator()(const NeighIn& image,
|
|
|
|
const vtkm::exec::BoundaryState& boundary,
|
2023-05-22 19:03:23 +00:00
|
|
|
TOut& moment) const
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2023-05-22 19:03:23 +00:00
|
|
|
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<ComponentType>::ZeroInitialization();
|
|
|
|
}
|
2019-07-16 20:35:53 +00:00
|
|
|
|
|
|
|
// Clamp the radius to the dataset bounds (discard out-of-bounds points).
|
2019-10-16 13:47:29 +00:00
|
|
|
const auto minRadius = boundary.ClampNeighborIndex(-this->RadiusDiscrete);
|
|
|
|
const auto maxRadius = boundary.ClampNeighborIndex(this->RadiusDiscrete);
|
2019-07-16 20:35:53 +00:00
|
|
|
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::Vec3f_64 radius;
|
2019-07-16 20:35:53 +00:00
|
|
|
for (vtkm::IdComponent k = minRadius[2]; k <= maxRadius[2]; ++k)
|
2019-04-23 14:57:35 +00:00
|
|
|
{
|
2019-10-16 13:47:29 +00:00
|
|
|
if (k > -this->RadiusDiscrete[2] && boundary.IJK[2] + k == 0)
|
2019-07-16 20:35:53 +00:00
|
|
|
{ // Don't double count samples that exist on other nodes:
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-16 13:47:29 +00:00
|
|
|
radius[2] = k * 1. / this->RadiusDiscrete[2];
|
2019-07-16 20:35:53 +00:00
|
|
|
|
|
|
|
for (vtkm::IdComponent j = minRadius[1]; j <= maxRadius[1]; ++j)
|
2019-04-23 14:57:35 +00:00
|
|
|
{
|
2019-10-16 13:47:29 +00:00
|
|
|
if (j > -this->RadiusDiscrete[1] && boundary.IJK[1] + j == 0)
|
2019-07-16 20:35:53 +00:00
|
|
|
{ // Don't double count samples that exist on other nodes:
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-16 13:47:29 +00:00
|
|
|
radius[1] = j * 1. / this->RadiusDiscrete[1];
|
2019-07-16 20:35:53 +00:00
|
|
|
|
|
|
|
for (vtkm::IdComponent i = minRadius[0]; i <= maxRadius[0]; ++i)
|
2019-04-23 22:34:07 +00:00
|
|
|
{
|
2019-10-16 13:47:29 +00:00
|
|
|
if (i > -this->RadiusDiscrete[0] && boundary.IJK[0] + i == 0)
|
2019-07-16 20:35:53 +00:00
|
|
|
{ // Don't double count samples that exist on other nodes:
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-16 13:47:29 +00:00
|
|
|
radius[0] = i * 1. / this->RadiusDiscrete[0];
|
2019-07-16 20:35:53 +00:00
|
|
|
|
2019-10-16 13:47:29 +00:00
|
|
|
if (vtkm::Dot(radius, radius) <= 1)
|
2019-07-24 15:32:03 +00:00
|
|
|
{
|
2023-05-22 19:03:23 +00:00
|
|
|
ComponentType multiplier = static_cast<ComponentType>(
|
|
|
|
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];
|
|
|
|
}
|
2019-07-24 15:32:03 +00:00
|
|
|
}
|
2019-04-23 22:34:07 +00:00
|
|
|
}
|
2019-04-23 14:57:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
// For variable sized Vecs, need to iterate over each component.
|
|
|
|
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
|
|
|
|
{
|
|
|
|
moment[componentI] *= static_cast<ComponentType>(this->SpacingProduct);
|
|
|
|
}
|
2019-04-23 14:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-10-16 13:47:29 +00:00
|
|
|
vtkm::Vec3i_32 RadiusDiscrete;
|
2022-02-07 17:51:04 +00:00
|
|
|
const vtkm::Float64 SpacingProduct;
|
2019-04-23 14:57:35 +00:00
|
|
|
const int p;
|
|
|
|
const int q;
|
2019-05-20 20:55:12 +00:00
|
|
|
const int r;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ComputeMoments
|
|
|
|
{
|
|
|
|
public:
|
2022-02-07 17:03:08 +00:00
|
|
|
ComputeMoments(double _radius, const vtkm::Vec3f& _spacing)
|
|
|
|
: Radius(_radius)
|
|
|
|
, Spacing(_spacing)
|
2019-06-17 18:27:52 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-01-04 22:38:18 +00:00
|
|
|
class ResolveUnknownCellSet
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
|
|
|
public:
|
2023-05-22 19:03:23 +00:00
|
|
|
template <typename T>
|
2019-05-20 20:55:12 +00:00
|
|
|
void operator()(const vtkm::cont::CellSetStructured<2>& input,
|
2023-05-22 19:03:23 +00:00
|
|
|
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
|
2022-02-07 17:51:04 +00:00
|
|
|
vtkm::Vec3f spacing,
|
|
|
|
vtkm::Float64 radius,
|
2019-07-24 15:32:03 +00:00
|
|
|
int maxOrder,
|
|
|
|
vtkm::cont::DataSet& output) const
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2019-07-24 15:32:03 +00:00
|
|
|
using WorkletType = vtkm::worklet::moments::ComputeMoments2D;
|
|
|
|
using DispatcherType = vtkm::worklet::DispatcherPointNeighborhood<WorkletType>;
|
|
|
|
|
|
|
|
for (int order = 0; order <= maxOrder; ++order)
|
|
|
|
{
|
|
|
|
for (int p = 0; p <= order; ++p)
|
|
|
|
{
|
|
|
|
const int q = order - p;
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
vtkm::cont::ArrayHandleRuntimeVec<T> moments{ pixels.GetNumberOfComponents() };
|
2019-07-24 15:32:03 +00:00
|
|
|
|
2022-02-07 17:51:04 +00:00
|
|
|
DispatcherType dispatcher(WorkletType{ spacing, radius, p, q });
|
2019-07-24 15:32:03 +00:00
|
|
|
dispatcher.Invoke(input, pixels, moments);
|
|
|
|
|
|
|
|
std::string fieldName = std::string("index") + std::string(p, '0') + std::string(q, '1');
|
|
|
|
|
|
|
|
vtkm::cont::Field momentsField(
|
2022-03-17 17:02:37 +00:00
|
|
|
fieldName, vtkm::cont::Field::Association::Points, moments);
|
2019-07-24 15:32:03 +00:00
|
|
|
output.AddField(momentsField);
|
|
|
|
}
|
|
|
|
}
|
2019-05-20 20:55:12 +00:00
|
|
|
}
|
2019-06-17 18:27:52 +00:00
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
template <typename T>
|
2019-05-20 20:55:12 +00:00
|
|
|
void operator()(const vtkm::cont::CellSetStructured<3>& input,
|
2023-05-22 19:03:23 +00:00
|
|
|
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
|
2022-02-07 17:51:04 +00:00
|
|
|
vtkm::Vec3f spacing,
|
|
|
|
vtkm::Float64 radius,
|
2019-07-24 15:32:03 +00:00
|
|
|
int maxOrder,
|
|
|
|
vtkm::cont::DataSet& output) const
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2019-07-24 15:32:03 +00:00
|
|
|
using WorkletType = vtkm::worklet::moments::ComputeMoments3D;
|
|
|
|
using DispatcherType = vtkm::worklet::DispatcherPointNeighborhood<WorkletType>;
|
|
|
|
|
|
|
|
for (int order = 0; order <= maxOrder; ++order)
|
|
|
|
{
|
|
|
|
for (int r = 0; r <= order; ++r)
|
|
|
|
{
|
|
|
|
const int qMax = order - r;
|
|
|
|
for (int q = 0; q <= qMax; ++q)
|
|
|
|
{
|
|
|
|
const int p = order - r - q;
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
vtkm::cont::ArrayHandleRuntimeVec<T> moments{ pixels.GetNumberOfComponents() };
|
2019-07-24 15:32:03 +00:00
|
|
|
|
2022-02-07 17:51:04 +00:00
|
|
|
DispatcherType dispatcher(WorkletType{ spacing, radius, p, q, r });
|
2019-07-24 15:32:03 +00:00
|
|
|
dispatcher.Invoke(input, pixels, moments);
|
|
|
|
|
|
|
|
std::string fieldName = std::string("index") + std::string(p, '0') +
|
|
|
|
std::string(q, '1') + std::string(r, '2');
|
|
|
|
|
|
|
|
vtkm::cont::Field momentsField(
|
2022-03-17 17:02:37 +00:00
|
|
|
fieldName, vtkm::cont::Field::Association::Points, moments);
|
2019-07-24 15:32:03 +00:00
|
|
|
output.AddField(momentsField);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-20 20:55:12 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-05-22 19:03:23 +00:00
|
|
|
template <typename T>
|
2022-01-04 22:38:18 +00:00
|
|
|
void Run(const vtkm::cont::UnknownCellSet& input,
|
2023-05-22 19:03:23 +00:00
|
|
|
const vtkm::cont::ArrayHandleRecombineVec<T>& pixels,
|
2019-07-24 15:32:03 +00:00
|
|
|
int maxOrder,
|
|
|
|
vtkm::cont::DataSet& output) const
|
2019-05-20 20:55:12 +00:00
|
|
|
{
|
2019-12-07 04:32:36 +00:00
|
|
|
input.ResetCellSetList(vtkm::cont::CellSetListStructured())
|
2022-01-04 22:38:18 +00:00
|
|
|
.CastAndCall(ResolveUnknownCellSet(), pixels, this->Spacing, this->Radius, maxOrder, output);
|
2019-05-20 20:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-02-07 17:51:04 +00:00
|
|
|
const vtkm::Float64 Radius;
|
2022-02-07 17:03:08 +00:00
|
|
|
const vtkm::Vec3f Spacing;
|
2019-04-23 14:57:35 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // vtk_m_worklet_moments_ComputeMoments_h
|