Implement Flying Edges for all structured CellSets

In addition to  using uniform coordinates, the ContourFlyingEdges filter can now process any type of coordinate system, making the  filter use Flying Edges in more cases
This commit is contained in:
Louis Gombert 2023-04-28 16:32:11 +02:00
parent a36415ff2b
commit 1538fc02fb
11 changed files with 212 additions and 164 deletions

@ -0,0 +1,5 @@
# Implement Flying Edges for structured cellsets with rectilinear and curvilinear coordinates
When Flying Edges was introduced to compute contours of a 3D structured cellset, it could only process uniform coordinates. This limitation is now lifted : an alternative interpolation function can be used in the fourth pass of the algorithm in order to support rectilinear and curvilinear coordinate systems.
Accordingly, the `Contour` filter now calls `ContourFlyingEdges` instead of `ContourMarchingCells` for these newly supported cases.

@ -13,7 +13,7 @@
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/contour/Contour.h>
#include <vtkm/filter/contour/ContourMarchingCells.h>
namespace
{
@ -72,13 +72,7 @@ void TestPointMerging()
vtkm::cont::testing::MakeTestDataSet makeDataSet;
vtkm::cont::DataSet baseData = makeDataSet.Make3DUniformDataSet3(vtkm::Id3(4, 4, 4));
//Convert the baseData implicit points to explicit points, since the contour
//filter for uniform data always does point merging
vtkm::cont::ArrayHandle<vtkm::Vec3f> newcoords;
vtkm::cont::ArrayCopy(baseData.GetCoordinateSystem().GetData(), newcoords);
baseData.AddPointField(baseData.GetCoordinateSystemName(), newcoords);
vtkm::filter::contour::Contour marchingCubes;
vtkm::filter::contour::ContourMarchingCells marchingCubes;
marchingCubes.SetIsoValue(0.05);
marchingCubes.SetMergeDuplicatePoints(false);
marchingCubes.SetActiveField("pointvar");

@ -34,11 +34,8 @@ vtkm::cont::DataSet Contour::DoExecute(const vtkm::cont::DataSet& inDataSet)
auto inCoords = inDataSet.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex()).GetData();
std::unique_ptr<vtkm::filter::contour::AbstractContour> implementation;
// For now, Flying Edges is only used for 3D Structured CellSets,
// using Uniform coordinates.
if (inCellSet.template IsType<vtkm::cont::CellSetStructured<3>>() &&
inCoords.template IsType<
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>>())
// Flying Edges is only used for 3D Structured CellSets
if (inCellSet.template IsType<vtkm::cont::CellSetStructured<3>>())
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Using flying edges");
implementation.reset(new vtkm::filter::contour::ContourFlyingEdges);

@ -44,13 +44,10 @@ vtkm::cont::DataSet ContourFlyingEdges::DoExecute(const vtkm::cont::DataSet& inD
const vtkm::cont::CoordinateSystem& inCoords =
inDataSet.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex());
if (!inCellSet.template IsType<vtkm::cont::CellSetStructured<3>>() ||
!inCoords.GetData()
.template IsType<
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>>())
if (!inCellSet.template IsType<vtkm::cont::CellSetStructured<3>>())
{
throw vtkm::cont::ErrorFilterExecution("This filter is only available for 3-Dimensional "
"Structured Cell Sets using uniform point coordinates.");
"Structured Cell Sets");
}
// Get the CellSet's known dynamic type
@ -74,22 +71,11 @@ vtkm::cont::DataSet ContourFlyingEdges::DoExecute(const vtkm::cont::DataSet& inD
if (this->GenerateNormals && !this->GetComputeFastNormals())
{
outputCells = worklet.Run(
ivalues,
inputCells,
inCoords.GetData().AsArrayHandle<vtkm::cont::ArrayHandleUniformPointCoordinates>(),
concrete,
vertices,
normals);
outputCells = worklet.Run(ivalues, inputCells, inCoords, concrete, vertices, normals);
}
else
{
outputCells = worklet.Run(
ivalues,
inputCells,
inCoords.GetData().AsArrayHandle<vtkm::cont::ArrayHandleUniformPointCoordinates>(),
concrete,
vertices);
outputCells = worklet.Run(ivalues, inputCells, inCoords, concrete, vertices);
}
};

@ -176,24 +176,12 @@ public:
void TestUnsupportedFlyingEdges() const
{
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::cont::DataSet rectilinearDataset = maker.Make3DRectilinearDataSet0();
vtkm::cont::DataSet explicitDataSet = maker.Make3DExplicitDataSet0();
vtkm::filter::contour::ContourFlyingEdges filter;
filter.SetIsoValue(2.0);
filter.SetActiveField("pointvar");
try
{
filter.Execute(rectilinearDataset);
VTKM_TEST_FAIL("Flying Edges filter should not run on datasets with rectilinear coordinates");
}
catch (vtkm::cont::ErrorFilterExecution&)
{
std::cout << "Execution successfully aborted" << std::endl;
}
try
{
filter.Execute(explicitDataSet);
@ -205,6 +193,58 @@ public:
}
}
template <typename ContourFilterType>
void TestNonUniformStructured() const
{
auto pathname =
vtkm::cont::testing::Testing::DataPath("rectilinear/simple_rectilinear1_ascii.vtk");
vtkm::io::VTKDataSetReader reader(pathname);
vtkm::cont::DataSet rectilinearDataset = reader.ReadDataSet();
// Single-cell contour
ContourFilterType filter;
filter.SetActiveField("var");
filter.SetIsoValue(2.0);
vtkm::cont::DataSet outputSingleCell = filter.Execute(rectilinearDataset);
auto coordinates = outputSingleCell.GetCoordinateSystem()
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Vec3f>>();
VTKM_TEST_ASSERT(outputSingleCell.GetNumberOfPoints() == 3,
"Wrong number of points in rectilinear contour");
VTKM_TEST_ASSERT(outputSingleCell.GetNumberOfCells() == 1,
"Wrong number of cells in rectilinear contour");
VTKM_TEST_ASSERT(outputSingleCell.GetCellSet().GetCellShape(0) == vtkm::CELL_SHAPE_TRIANGLE,
"Wrong contour cell shape");
auto expectedCoordinates =
vtkm::cont::make_ArrayHandle<vtkm::Vec3f>({ vtkm::Vec3f{ 10.0f, -10.0f, 9.66341f },
vtkm::Vec3f{ 9.30578f, -10.0f, 10.0f },
vtkm::Vec3f{ 10.0f, -9.78842f, 10.0f } });
VTKM_TEST_ASSERT(test_equal_ArrayHandles(coordinates, expectedCoordinates),
"Wrong contour coordinates");
// Generating normals triggers a different worklet for Flying Edges pass 4,
// But it should not change anything on the contour itself.
filter.SetGenerateNormals(true);
vtkm::cont::DataSet outputNormals = filter.Execute(rectilinearDataset);
coordinates = outputSingleCell.GetCoordinateSystem()
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Vec3f>>();
VTKM_TEST_ASSERT(test_equal_ArrayHandles(coordinates, expectedCoordinates),
"Wrong contour coordinates");
// Full contour
filter.SetIsoValue(3.0);
filter.SetGenerateNormals(false);
vtkm::cont::DataSet output = filter.Execute(rectilinearDataset);
VTKM_TEST_ASSERT(output.GetNumberOfPoints() == 93,
"Wrong number of points in rectilinear contour");
VTKM_TEST_ASSERT(output.GetNumberOfCells() == 144,
"Wrong number of cells in rectilinear contour");
}
void operator()() const
{
this->TestContourUniformGrid<vtkm::filter::contour::Contour>(72);
@ -220,6 +260,10 @@ public:
this->TestContourWedges<vtkm::filter::contour::Contour>();
this->TestContourWedges<vtkm::filter::contour::ContourMarchingCells>();
this->TestNonUniformStructured<vtkm::filter::contour::Contour>();
this->TestNonUniformStructured<vtkm::filter::contour::ContourFlyingEdges>();
this->TestNonUniformStructured<vtkm::filter::contour::ContourMarchingCells>();
this->TestUnsupportedFlyingEdges();
}

@ -67,13 +67,14 @@ public:
// Filter called without normals generation
template <typename ValueType,
typename CoordsType,
typename StorageTagField,
typename CoordinateType,
typename StorageTagVertices>
vtkm::cont::CellSetSingleType<> Run(
const std::vector<ValueType>& isovalues,
const vtkm::cont::CellSetStructured<3>& cells,
const vtkm::cont::ArrayHandleUniformPointCoordinates& coordinateSystem,
const CoordsType& coordinateSystem,
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices>& vertices)
{
@ -87,6 +88,7 @@ public:
// Filter called with normals generation
template <typename ValueType,
typename CoordsType,
typename StorageTagField,
typename CoordinateType,
typename StorageTagVertices,
@ -94,7 +96,7 @@ public:
vtkm::cont::CellSetSingleType<> Run(
const std::vector<ValueType>& isovalues,
const vtkm::cont::CellSetStructured<3>& cells,
const vtkm::cont::ArrayHandleUniformPointCoordinates& coordinateSystem,
const CoordsType& coordinateSystem,
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices>& vertices,
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagNormals>& normals)

@ -41,6 +41,7 @@ vtkm::Id extend_by(vtkm::cont::ArrayHandle<T, S>& handle, vtkm::Id size)
//----------------------------------------------------------------------------
template <typename ValueType,
typename CoordsType,
typename StorageTagField,
typename StorageTagVertices,
typename StorageTagNormals,
@ -48,7 +49,7 @@ template <typename ValueType,
typename NormalType>
vtkm::cont::CellSetSingleType<> execute(
const vtkm::cont::CellSetStructured<3>& cells,
const vtkm::cont::ArrayHandleUniformPointCoordinates& coordinateSystem,
const CoordsType coordinateSystem,
const std::vector<ValueType>& isovalues,
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& inputField,
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices>& points,
@ -56,18 +57,10 @@ vtkm::cont::CellSetSingleType<> execute(
vtkm::worklet::contour::CommonState& sharedState)
{
vtkm::cont::Invoker invoke;
vtkm::Vec3f origin, spacing;
{ //extract out the origin and spacing as these are needed for Pass4 to properly
//interpolate the new points
auto portal = coordinateSystem.ReadPortal();
origin = portal.GetOrigin();
spacing = portal.GetSpacing();
}
auto pdims = cells.GetPointDimensions();
vtkm::cont::ArrayHandle<vtkm::UInt8> edgeCases;
edgeCases.Allocate(coordinateSystem.GetNumberOfValues());
edgeCases.Allocate(coordinateSystem.GetData().GetNumberOfValues());
vtkm::cont::CellSetStructured<2> metaDataMesh2D;
vtkm::cont::ArrayHandle<vtkm::Id> metaDataLinearSums; //per point of metaDataMesh
@ -158,8 +151,7 @@ vtkm::cont::CellSetSingleType<> execute(
{
VTKM_LOG_SCOPE(vtkm::cont::LogLevel::Perf, "FlyingEdges Pass4");
launchComputePass4 pass4(
pdims, origin, spacing, multiContourCellOffset, multiContourPointOffset);
auto pass4 = launchComputePass4(pdims, multiContourCellOffset, multiContourPointOffset);
detail::extend_by(points, newPointSize);
if (sharedState.GenerateNormals)
@ -171,6 +163,7 @@ vtkm::cont::CellSetSingleType<> execute(
pass4,
newPointSize,
isoval,
coordinateSystem,
inputField,
edgeCases,
metaDataMesh2D,

@ -28,20 +28,14 @@ namespace flying_edges
struct launchComputePass4
{
vtkm::Id3 PointDims;
vtkm::Vec3f Origin;
vtkm::Vec3f Spacing;
vtkm::Id CellWriteOffset;
vtkm::Id PointWriteOffset;
launchComputePass4(const vtkm::Id3& pdims,
const vtkm::Vec3f& origin,
const vtkm::Vec3f& spacing,
vtkm::Id multiContourCellOffset,
vtkm::Id multiContourPointOffset)
: PointDims(pdims)
, Origin(origin)
, Spacing(spacing)
, CellWriteOffset(multiContourCellOffset)
, PointWriteOffset(multiContourPointOffset)
{
@ -49,6 +43,7 @@ struct launchComputePass4
template <typename DeviceAdapterTag,
typename T,
typename CoordsType,
typename StorageTagField,
typename MeshSums,
typename PointType,
@ -56,6 +51,7 @@ struct launchComputePass4
VTKM_CONT bool LaunchXAxis(DeviceAdapterTag device,
vtkm::Id vtkmNotUsed(newPointSize),
T isoval,
CoordsType coordinateSystem,
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
vtkm::cont::ArrayHandle<vtkm::UInt8> edgeCases,
vtkm::cont::CellSetStructured<2>& metaDataMesh2D,
@ -71,12 +67,8 @@ struct launchComputePass4
vtkm::cont::Invoker invoke(device);
if (sharedState.GenerateNormals)
{
ComputePass4XWithNormals<T> worklet4(isoval,
this->PointDims,
this->Origin,
this->Spacing,
this->CellWriteOffset,
this->PointWriteOffset);
ComputePass4XWithNormals<T> worklet4(
isoval, this->PointDims, this->CellWriteOffset, this->PointWriteOffset);
invoke(worklet4,
metaDataMesh2D,
metaDataSums,
@ -84,6 +76,7 @@ struct launchComputePass4
metaDataMax,
metaDataNumTris,
edgeCases,
coordinateSystem,
inputField,
triangle_topology,
sharedState.InterpolationEdgeIds,
@ -94,12 +87,8 @@ struct launchComputePass4
}
else
{
ComputePass4X<T> worklet4(isoval,
this->PointDims,
this->Origin,
this->Spacing,
this->CellWriteOffset,
this->PointWriteOffset);
ComputePass4X<T> worklet4(
isoval, this->PointDims, this->CellWriteOffset, this->PointWriteOffset);
invoke(worklet4,
metaDataMesh2D,
metaDataSums,
@ -107,6 +96,7 @@ struct launchComputePass4
metaDataMax,
metaDataNumTris,
edgeCases,
coordinateSystem,
inputField,
triangle_topology,
sharedState.InterpolationEdgeIds,
@ -120,6 +110,7 @@ struct launchComputePass4
template <typename DeviceAdapterTag,
typename T,
typename CoordsType,
typename StorageTagField,
typename MeshSums,
typename PointType,
@ -127,6 +118,7 @@ struct launchComputePass4
VTKM_CONT bool LaunchYAxis(DeviceAdapterTag device,
vtkm::Id newPointSize,
T isoval,
CoordsType coordinateSystem,
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
vtkm::cont::ArrayHandle<vtkm::UInt8> edgeCases,
vtkm::cont::CellSetStructured<2>& metaDataMesh2D,
@ -157,11 +149,8 @@ struct launchComputePass4
sharedState.CellIdMap);
//This needs to be done on array handle view ( start = this->PointWriteOffset, len = newPointSize)
ComputePass5Y<T> worklet5(this->PointDims,
this->Origin,
this->Spacing,
this->PointWriteOffset,
sharedState.GenerateNormals);
ComputePass5Y<T> worklet5(this->PointDims, this->PointWriteOffset, sharedState.GenerateNormals);
invoke(worklet5,
vtkm::cont::make_ArrayHandleView(
sharedState.InterpolationEdgeIds, this->PointWriteOffset, newPointSize),
@ -169,6 +158,7 @@ struct launchComputePass4
sharedState.InterpolationWeights, this->PointWriteOffset, newPointSize),
vtkm::cont::make_ArrayHandleView(points, this->PointWriteOffset, newPointSize),
inputField,
coordinateSystem,
normals);
return true;

@ -32,9 +32,6 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
{
vtkm::Id3 PointDims;
vtkm::Vec3f Origin;
vtkm::Vec3f Spacing;
T IsoValue;
vtkm::Id CellWriteOffset;
@ -43,13 +40,9 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
ComputePass4X() {}
ComputePass4X(T value,
const vtkm::Id3& pdims,
const vtkm::Vec3f& origin,
const vtkm::Vec3f& spacing,
vtkm::Id multiContourCellOffset,
vtkm::Id multiContourPointOffset)
: PointDims(pdims)
, Origin(origin)
, Spacing(spacing)
, IsoValue(value)
, CellWriteOffset(multiContourCellOffset)
, PointWriteOffset(multiContourPointOffset)
@ -62,6 +55,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
FieldInPoint axis_maxs,
WholeArrayIn cell_tri_count,
WholeArrayIn edgeData,
WholeArrayIn coords,
WholeArrayIn data,
WholeArrayOut connectivity,
WholeArrayOut edgeIds,
@ -69,13 +63,14 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
WholeArrayOut inputCellIds,
WholeArrayOut points);
using ExecutionSignature =
void(ThreadIndices, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, WorkIndex);
void(ThreadIndices, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, WorkIndex);
template <typename ThreadIndices,
typename FieldInPointId3,
typename FieldInPointId,
typename WholeTriField,
typename WholeEdgeField,
typename WholeCoordsField,
typename WholeDataField,
typename WholeConnField,
typename WholeEdgeIdField,
@ -88,6 +83,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
const FieldInPointId& axis_maxs,
const WholeTriField& cellTriCount,
const WholeEdgeField& edges,
const WholeCoordsField& coords,
const WholeDataField& field,
const WholeConnField& conn,
const WholeEdgeIdField& interpolatedEdgeIds,
@ -141,6 +137,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
field,
interpolatedEdgeIds,
weights,
coords,
points,
state.startPos,
increments,
@ -158,12 +155,14 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
template <typename WholeDataField,
typename WholeIEdgeField,
typename WholeWeightField,
typename WholeCoordsField,
typename WholePointField>
VTKM_EXEC inline void Generate(const vtkm::Vec<vtkm::UInt8, 3>& boundaryStatus,
const vtkm::Id3& ijk,
const WholeDataField& field,
const WholeIEdgeField& interpolatedEdgeIds,
const WholeWeightField& weights,
const WholeCoordsField coords,
const WholePointField& points,
const vtkm::Id4& startPos,
const vtkm::Id3& incs,
@ -188,7 +187,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
interpolatedEdgeIds.Set(writeIndex, pos);
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto coord = this->InterpolateCoordinate(t, ijk, ijk + vtkm::Id3{ 1, 0, 0 });
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk + vtkm::Id3{ 1, 0, 0 });
points.Set(writeIndex, coord);
}
if (edgeUses[4])
@ -201,7 +200,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
interpolatedEdgeIds.Set(writeIndex, pos);
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto coord = this->InterpolateCoordinate(t, ijk, ijk + vtkm::Id3{ 0, 1, 0 });
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk + vtkm::Id3{ 0, 1, 0 });
points.Set(writeIndex, coord);
}
if (edgeUses[8])
@ -214,7 +213,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
interpolatedEdgeIds.Set(writeIndex, pos);
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto coord = this->InterpolateCoordinate(t, ijk, ijk + vtkm::Id3{ 0, 0, 1 });
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk + vtkm::Id3{ 0, 0, 1 });
points.Set(writeIndex, coord);
}
}
@ -231,30 +230,30 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
const bool onZ = boundaryStatus[AxisToSum::zindex] & FlyingEdges3D::MaxBoundary;
if (onX) //+x boundary
{
this->InterpolateEdge(ijk, pos[0], incs, 5, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 9, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 5, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
this->InterpolateEdge(ijk, pos[0], incs, 9, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
if (onY) //+x +y
{
this->InterpolateEdge(ijk, pos[0], incs, 11, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 11, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
}
if (onZ) //+x +z
{
this->InterpolateEdge(ijk, pos[0], incs, 7, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 7, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
}
}
if (onY) //+y boundary
{
this->InterpolateEdge(ijk, pos[0], incs, 1, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 10, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 1, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
this->InterpolateEdge(ijk, pos[0], incs, 10, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
if (onZ) //+y +z boundary
{
this->InterpolateEdge(ijk, pos[0], incs, 3, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 3, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
}
}
if (onZ) //+z boundary
{
this->InterpolateEdge(ijk, pos[0], incs, 2, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 6, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points);
this->InterpolateEdge(ijk, pos[0], incs, 2, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
this->InterpolateEdge(ijk, pos[0], incs, 6, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points);
}
// clang-format on
}
@ -264,6 +263,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
template <typename WholeField,
typename WholeIEdgeField,
typename WholeWeightField,
typename WholeCoordsField,
typename WholePointField>
VTKM_EXEC inline void InterpolateEdge(const vtkm::Id3& ijk,
vtkm::Id currentIdx,
@ -274,6 +274,7 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
const WholeField& field,
const WholeIEdgeField& interpolatedEdgeIds,
const WholeWeightField& weights,
const WholeCoordsField& coords,
const WholePointField& points) const
{
using AxisToSum = SumXAxis;
@ -300,30 +301,49 @@ struct ComputePass4X : public vtkm::worklet::WorkletVisitCellsWithPoints
T t = static_cast<T>((this->IsoValue - s0) / (s1 - s0));
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto coord = this->InterpolateCoordinate(t, ijk + offsets1, ijk + offsets2);
auto coord = this->InterpolateCoordinate(coords, t, ijk + offsets1, ijk + offsets2);
points.Set(writeIndex, coord);
}
// Fast interpolation method for uniform coordinates
//----------------------------------------------------------------------------
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(
vtkm::internal::ArrayPortalUniformPointCoordinates coords,
T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
{
return vtkm::Vec3f(
this->Origin[0] +
this->Spacing[0] *
coords.GetOrigin()[0] +
coords.GetSpacing()[0] *
(static_cast<vtkm::FloatDefault>(ijk0[0]) +
static_cast<vtkm::FloatDefault>(t) * static_cast<vtkm::FloatDefault>(ijk1[0] - ijk0[0])),
this->Origin[1] +
this->Spacing[1] *
coords.GetOrigin()[1] +
coords.GetSpacing()[1] *
(static_cast<vtkm::FloatDefault>(ijk0[1]) +
static_cast<vtkm::FloatDefault>(t) * static_cast<vtkm::FloatDefault>(ijk1[1] - ijk0[1])),
this->Origin[2] +
this->Spacing[2] *
coords.GetOrigin()[2] +
coords.GetSpacing()[2] *
(static_cast<vtkm::FloatDefault>(ijk0[2]) +
static_cast<vtkm::FloatDefault>(t) *
static_cast<vtkm::FloatDefault>(ijk1[2] - ijk0[2])));
}
// Interpolation for explicit coordinates
//----------------------------------------------------------------------------
template <typename CoordsPortal>
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(CoordsPortal coords,
T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
{
return (1.0f - static_cast<vtkm::FloatDefault>(t)) *
coords.Get(ijk0[0] + this->PointDims[0] * ijk0[1] +
this->PointDims[0] * this->PointDims[1] * ijk0[2]) +
static_cast<vtkm::FloatDefault>(t) *
coords.Get(ijk1[0] + this->PointDims[0] * ijk1[1] +
this->PointDims[0] * this->PointDims[1] * ijk1[2]);
}
};
}
}

@ -31,9 +31,6 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
{
vtkm::Id3 PointDims;
vtkm::Vec3f Origin;
vtkm::Vec3f Spacing;
T IsoValue;
vtkm::Id CellWriteOffset;
@ -42,13 +39,9 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
ComputePass4XWithNormals() {}
ComputePass4XWithNormals(T value,
const vtkm::Id3& pdims,
const vtkm::Vec3f& origin,
const vtkm::Vec3f& spacing,
vtkm::Id multiContourCellOffset,
vtkm::Id multiContourPointOffset)
: PointDims(pdims)
, Origin(origin)
, Spacing(spacing)
, IsoValue(value)
, CellWriteOffset(multiContourCellOffset)
, PointWriteOffset(multiContourPointOffset)
@ -61,6 +54,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
FieldInPoint axis_maxs,
WholeArrayIn cell_tri_count,
WholeArrayIn edgeData,
WholeArrayIn coords,
WholeArrayIn data,
WholeArrayOut connectivity,
WholeArrayOut edgeIds,
@ -69,13 +63,14 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
WholeArrayOut points,
WholeArrayOut normals);
using ExecutionSignature =
void(ThreadIndices, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, WorkIndex);
void(ThreadIndices, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, WorkIndex);
template <typename ThreadIndices,
typename FieldInPointId3,
typename FieldInPointId,
typename WholeTriField,
typename WholeEdgeField,
typename WholeCoordsField,
typename WholeDataField,
typename WholeConnField,
typename WholeEdgeIdField,
@ -89,6 +84,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
const FieldInPointId& axis_maxs,
const WholeTriField& cellTriCount,
const WholeEdgeField& edges,
const WholeCoordsField& coords,
const WholeDataField& field,
const WholeConnField& conn,
const WholeEdgeIdField& interpolatedEdgeIds,
@ -144,6 +140,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
field,
interpolatedEdgeIds,
weights,
coords,
points,
normals,
state.startPos,
@ -162,6 +159,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
template <typename WholeDataField,
typename WholeIEdgeField,
typename WholeWeightField,
typename WholeCoordsField,
typename WholePointField,
typename WholeNormalField>
VTKM_EXEC inline void Generate(const vtkm::Vec<vtkm::UInt8, 3>& boundaryStatus,
@ -169,6 +167,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
const WholeDataField& field,
const WholeIEdgeField& interpolatedEdgeIds,
const WholeWeightField& weights,
const WholeCoordsField coords,
const WholePointField& points,
const WholeNormalField& normals,
const vtkm::Id4& startPos,
@ -197,7 +196,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto ijk1 = ijk + vtkm::Id3{ 1, 0, 0 };
auto coord = this->InterpolateCoordinate(t, ijk, ijk1);
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk1);
points.Set(writeIndex, coord);
//gradient generation
@ -216,7 +215,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto ijk1 = ijk + vtkm::Id3{ 0, 1, 0 };
auto coord = this->InterpolateCoordinate(t, ijk, ijk1);
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk1);
points.Set(writeIndex, coord);
//gradient generation
@ -235,7 +234,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto ijk1 = ijk + vtkm::Id3{ 0, 0, 1 };
auto coord = this->InterpolateCoordinate(t, ijk, ijk1);
auto coord = this->InterpolateCoordinate(coords, t, ijk, ijk1);
points.Set(writeIndex, coord);
//gradient generation
@ -258,38 +257,38 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
if (onX) //+x boundary
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 5, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 5, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 9, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 9, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
if (onY) //+x +y
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 11, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 11, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
}
if (onZ) //+x +z
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 7, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 7, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
}
}
if (onY) //+y boundary
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 1, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 1, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 10, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 10, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
if (onZ) //+y +z boundary
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 3, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 3, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
}
}
if (onZ) //+z boundary
{
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 2, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 2, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
this->InterpolateEdge(
fullyInterior, ijk, pos[0], incs, 6, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, points, normals);
fullyInterior, ijk, pos[0], incs, 6, edgeUses, edgeIds, field, interpolatedEdgeIds, weights, coords, points, normals);
}
// clang-format on
}
@ -300,6 +299,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
typename WholeIEdgeField,
typename WholeWeightField,
typename WholePointField,
typename WholeCoordsField,
typename WholeNormalField>
VTKM_EXEC inline void InterpolateEdge(bool fullyInterior,
const vtkm::Id3& ijk,
@ -311,6 +311,7 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
const WholeField& field,
const WholeIEdgeField& interpolatedEdgeIds,
const WholeWeightField& weights,
const WholeCoordsField& coords,
const WholePointField& points,
const WholeNormalField& normals) const
{
@ -338,36 +339,55 @@ struct ComputePass4XWithNormals : public vtkm::worklet::WorkletVisitCellsWithPoi
T t = static_cast<T>((this->IsoValue - s0) / (s1 - s0));
weights.Set(writeIndex, static_cast<vtkm::FloatDefault>(t));
auto coord = this->InterpolateCoordinate(t, ijk + offsets1, ijk + offsets2);
auto coord = this->InterpolateCoordinate(coords, t, ijk + offsets1, ijk + offsets2);
points.Set(writeIndex, coord);
auto g0 = this->ComputeGradient(fullyInterior, ijk + offsets1, incs, iEdge[0], field);
auto g1 = this->ComputeGradient(fullyInterior, ijk + offsets2, incs, iEdge[1], field);
auto g0 = this->ComputeGradient(fullyInterior, ijk + offsets1, incs, iEdge[0], field);
g1 = g0 + (t * (g1 - g0));
normals.Set(writeIndex, vtkm::Normal(g1));
}
// Fast interpolation method for uniform coordinates
//----------------------------------------------------------------------------
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(
const vtkm::internal::ArrayPortalUniformPointCoordinates& coords,
T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
{
return vtkm::Vec3f(
this->Origin[0] +
this->Spacing[0] *
coords.GetOrigin()[0] +
coords.GetSpacing()[0] *
(static_cast<vtkm::FloatDefault>(ijk0[0]) +
static_cast<vtkm::FloatDefault>(t) * static_cast<vtkm::FloatDefault>(ijk1[0] - ijk0[0])),
this->Origin[1] +
this->Spacing[1] *
coords.GetOrigin()[1] +
coords.GetSpacing()[1] *
(static_cast<vtkm::FloatDefault>(ijk0[1]) +
static_cast<vtkm::FloatDefault>(t) * static_cast<vtkm::FloatDefault>(ijk1[1] - ijk0[1])),
this->Origin[2] +
this->Spacing[2] *
coords.GetOrigin()[2] +
coords.GetSpacing()[2] *
(static_cast<vtkm::FloatDefault>(ijk0[2]) +
static_cast<vtkm::FloatDefault>(t) *
static_cast<vtkm::FloatDefault>(ijk1[2] - ijk0[2])));
}
// Interpolation for explicit coordinates
//----------------------------------------------------------------------------
template <typename CoordsPortal>
inline VTKM_EXEC vtkm::Vec3f InterpolateCoordinate(const CoordsPortal& coords,
T t,
const vtkm::Id3& ijk0,
const vtkm::Id3& ijk1) const
{
return (1.0f - static_cast<vtkm::FloatDefault>(t)) *
coords.Get(ijk0[0] + this->PointDims[0] * ijk0[1] +
this->PointDims[0] * this->PointDims[1] * ijk0[2]) +
static_cast<vtkm::FloatDefault>(t) *
coords.Get(ijk1[0] + this->PointDims[0] * ijk1[1] +
this->PointDims[0] * this->PointDims[1] * ijk1[2]);
}
//----------------------------------------------------------------------------
template <typename WholeDataField>
VTKM_EXEC vtkm::Vec3f ComputeGradient(bool fullyInterior,

@ -276,17 +276,11 @@ struct ComputePass4Y : public vtkm::worklet::WorkletVisitCellsWithPoints
template <typename T>
struct ComputePass5Y : public vtkm::worklet::WorkletMapField
{
vtkm::internal::ArrayPortalUniformPointCoordinates Coordinates;
vtkm::Id3 PointDims;
vtkm::Id NormalWriteOffset;
ComputePass5Y() {}
ComputePass5Y(const vtkm::Id3& pdims,
const vtkm::Vec3f& origin,
const vtkm::Vec3f& spacing,
vtkm::Id normalWriteOffset,
bool generateNormals)
: Coordinates(pdims, origin, spacing)
ComputePass5Y(const vtkm::Id3& pdims, vtkm::Id normalWriteOffset, bool generateNormals)
: PointDims(pdims)
, NormalWriteOffset(normalWriteOffset)
{
if (!generateNormals)
@ -299,20 +293,25 @@ struct ComputePass5Y : public vtkm::worklet::WorkletMapField
FieldIn interpWeight,
FieldOut points,
WholeArrayIn field,
WholeArrayIn coords,
WholeArrayOut normals);
using ExecutionSignature = void(_1, _2, _3, _4, _5, WorkIndex);
using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, WorkIndex);
template <typename PT, typename WholeInputField, typename WholeNormalField>
template <typename PT,
typename WholeInputField,
typename WholeNormalField,
typename WholeCoordsField>
VTKM_EXEC void operator()(const vtkm::Id2& interpEdgeIds,
vtkm::FloatDefault weight,
vtkm::Vec<PT, 3>& outPoint,
const WholeInputField& field,
const WholeCoordsField& coords,
WholeNormalField& normals,
vtkm::Id oidx) const
{
{
vtkm::Vec3f point1 = this->Coordinates.Get(interpEdgeIds[0]);
vtkm::Vec3f point2 = this->Coordinates.Get(interpEdgeIds[1]);
vtkm::Vec3f point1 = coords.Get(interpEdgeIds[0]);
vtkm::Vec3f point2 = coords.Get(interpEdgeIds[1]);
outPoint = vtkm::Lerp(point1, point2, weight);
}
@ -320,15 +319,13 @@ struct ComputePass5Y : public vtkm::worklet::WorkletMapField
if (this->NormalWriteOffset >= 0)
{
vtkm::Vec<T, 3> g0, g1;
const vtkm::Id3& dims = this->Coordinates.GetDimensions();
vtkm::Id3 ijk{ interpEdgeIds[0] % dims[0],
(interpEdgeIds[0] / dims[0]) % dims[1],
interpEdgeIds[0] / (dims[0] * dims[1]) };
vtkm::Id3 ijk{ interpEdgeIds[0] % this->PointDims[0],
(interpEdgeIds[0] / this->PointDims[0]) % this->PointDims[1],
interpEdgeIds[0] / (this->PointDims[0] * this->PointDims[1]) };
vtkm::worklet::gradient::StructuredPointGradient gradient;
vtkm::exec::BoundaryState boundary(ijk, dims);
vtkm::exec::FieldNeighborhood<vtkm::internal::ArrayPortalUniformPointCoordinates>
coord_neighborhood(this->Coordinates, boundary);
vtkm::exec::BoundaryState boundary(ijk, this->PointDims);
vtkm::exec::FieldNeighborhood<WholeCoordsField> coord_neighborhood(coords, boundary);
vtkm::exec::FieldNeighborhood<WholeInputField> field_neighborhood(field, boundary);
@ -337,9 +334,9 @@ struct ComputePass5Y : public vtkm::worklet::WorkletMapField
gradient(boundary, coord_neighborhood, field_neighborhood, g0);
//compute the gradient at point 2. This optimization can be optimized
boundary.IJK = vtkm::Id3{ interpEdgeIds[1] % dims[0],
(interpEdgeIds[1] / dims[0]) % dims[1],
interpEdgeIds[1] / (dims[0] * dims[1]) };
boundary.IJK = vtkm::Id3{ interpEdgeIds[1] % this->PointDims[0],
(interpEdgeIds[1] / this->PointDims[0]) % this->PointDims[1],
interpEdgeIds[1] / (this->PointDims[0] * this->PointDims[1]) };
gradient(boundary, coord_neighborhood, field_neighborhood, g1);
vtkm::Vec3f n = vtkm::Lerp(g0, g1, weight);