mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
GhostCellClassify now more efficient as it uses WorkletPointNeighborhood
By using the dual of the cellset we can quickly compute the GhostCells of structured data using WorkletPointNeighborhood boundary condition object Using a 1024x1024x512 test grid we see the following perf: Master Serial : 5.658144 sec This MR Serial: 0.519684 sec Master OpenMP : 0.532256 sec This MR OpenMP: 0.080604 sec
This commit is contained in:
parent
1a70c6f9ed
commit
8c3a8da99b
@ -13,7 +13,7 @@
|
|||||||
namespace vtkm
|
namespace vtkm
|
||||||
{
|
{
|
||||||
|
|
||||||
enum struct CellClassification
|
enum CellClassification : vtkm::UInt8
|
||||||
{
|
{
|
||||||
NORMAL = 0, //Valid cell
|
NORMAL = 0, //Valid cell
|
||||||
GHOST = 1 << 0, //Ghost cell
|
GHOST = 1 << 0, //Ghost cell
|
||||||
|
@ -25,6 +25,8 @@ struct GhostCellClassifyPolicy : vtkm::filter::PolicyBase<GhostCellClassifyPolic
|
|||||||
class GhostCellClassify : public vtkm::filter::FilterDataSet<GhostCellClassify>
|
class GhostCellClassify : public vtkm::filter::FilterDataSet<GhostCellClassify>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using SupportedTypes = vtkm::ListTagBase<vtkm::UInt8>;
|
||||||
|
|
||||||
VTKM_CONT
|
VTKM_CONT
|
||||||
GhostCellClassify();
|
GhostCellClassify();
|
||||||
|
|
||||||
|
@ -15,9 +15,8 @@
|
|||||||
#include <vtkm/Types.h>
|
#include <vtkm/Types.h>
|
||||||
#include <vtkm/cont/ArrayCopy.h>
|
#include <vtkm/cont/ArrayCopy.h>
|
||||||
#include <vtkm/cont/ArrayHandle.h>
|
#include <vtkm/cont/ArrayHandle.h>
|
||||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
|
||||||
|
|
||||||
#include <vtkm/worklet/WorkletMapField.h>
|
#include <vtkm/worklet/WorkletPointNeighborhood.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -25,101 +24,68 @@ struct TypeUInt8 : vtkm::ListTagBase<vtkm::UInt8>
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStructuredGhostCells1D : public vtkm::worklet::WorkletMapField
|
class SetStructuredGhostCells1D : public vtkm::worklet::WorkletPointNeighborhood
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStructuredGhostCells1D(const vtkm::Id& dim, const vtkm::Id& numLayers = 1)
|
SetStructuredGhostCells1D(vtkm::IdComponent numLayers = 1)
|
||||||
: Dim(dim)
|
: NumLayers(numLayers)
|
||||||
, NumLayers(numLayers)
|
|
||||||
, Range(NumLayers, Dim - NumLayers)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
using ControlSignature = void(FieldIn, FieldOut);
|
using ControlSignature = void(CellSetIn, FieldOut);
|
||||||
using ExecutionSignature = void(_1, _2);
|
using ExecutionSignature = void(Boundary, _2);
|
||||||
|
|
||||||
template <typename T>
|
VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, vtkm::UInt8& value) const
|
||||||
VTKM_EXEC void operator()(const vtkm::Id& cellIndex, T& value) const
|
|
||||||
{
|
{
|
||||||
value = (Range.Contains(cellIndex) ? NormalCell : DuplicateCell);
|
const bool notOnBoundary = boundary.IsRadiusInXBoundary(this->NumLayers);
|
||||||
|
value = (notOnBoundary) ? vtkm::CellClassification::NORMAL : vtkm::CellClassification::GHOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vtkm::Id Dim;
|
vtkm::IdComponent NumLayers;
|
||||||
vtkm::Id NumLayers;
|
|
||||||
vtkm::RangeId Range;
|
|
||||||
static constexpr vtkm::UInt8 NormalCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::NORMAL);
|
|
||||||
static constexpr vtkm::UInt8 DuplicateCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::GHOST);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStructuredGhostCells2D : public vtkm::worklet::WorkletMapField
|
class SetStructuredGhostCells2D : public vtkm::worklet::WorkletPointNeighborhood
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStructuredGhostCells2D(const vtkm::Id2& dims, const vtkm::Id& numLayers = 1)
|
SetStructuredGhostCells2D(vtkm::IdComponent numLayers = 1)
|
||||||
: Dims(dims)
|
: NumLayers(numLayers)
|
||||||
, NumLayers(numLayers)
|
|
||||||
, Range(NumLayers, Dims[0] - NumLayers, NumLayers, Dims[1] - NumLayers)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
using ControlSignature = void(FieldIn, FieldOut);
|
using ControlSignature = void(CellSetIn, FieldOut);
|
||||||
using ExecutionSignature = void(_1, _2);
|
using ExecutionSignature = void(Boundary, _2);
|
||||||
|
|
||||||
template <typename T>
|
VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, vtkm::UInt8& value) const
|
||||||
VTKM_EXEC void operator()(const vtkm::Id& cellIndex, T& value) const
|
|
||||||
{
|
{
|
||||||
vtkm::Id2 ij(cellIndex % Dims[0], cellIndex / Dims[0]);
|
const bool notOnBoundary = boundary.IsRadiusInXBoundary(this->NumLayers) &&
|
||||||
|
boundary.IsRadiusInYBoundary(this->NumLayers);
|
||||||
value = (Range.Contains(ij) ? NormalCell : DuplicateCell);
|
value = (notOnBoundary) ? vtkm::CellClassification::NORMAL : vtkm::CellClassification::GHOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vtkm::Id2 Dims;
|
vtkm::IdComponent NumLayers;
|
||||||
vtkm::Id NumLayers;
|
|
||||||
vtkm::RangeId2 Range;
|
|
||||||
static constexpr vtkm::UInt8 NormalCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::NORMAL);
|
|
||||||
static constexpr vtkm::UInt8 DuplicateCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::GHOST);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStructuredGhostCells3D : public vtkm::worklet::WorkletMapField
|
class SetStructuredGhostCells3D : public vtkm::worklet::WorkletPointNeighborhood
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStructuredGhostCells3D(const vtkm::Id3& dims, const vtkm::Id& numLayers = 1)
|
SetStructuredGhostCells3D(vtkm::IdComponent numLayers = 1)
|
||||||
: Dims(dims)
|
: NumLayers(numLayers)
|
||||||
, NumLayers(numLayers)
|
|
||||||
, Range(NumLayers,
|
|
||||||
Dims[0] - NumLayers,
|
|
||||||
NumLayers,
|
|
||||||
Dims[1] - NumLayers,
|
|
||||||
NumLayers,
|
|
||||||
Dims[2] - NumLayers)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
using ControlSignature = void(FieldIn, FieldOut);
|
using ControlSignature = void(CellSetIn, FieldOut);
|
||||||
using ExecutionSignature = void(_1, _2);
|
using ExecutionSignature = void(Boundary, _2);
|
||||||
|
|
||||||
template <typename T>
|
VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, vtkm::UInt8& value) const
|
||||||
VTKM_EXEC void operator()(const vtkm::Id& cellIndex, T& value) const
|
|
||||||
{
|
{
|
||||||
vtkm::Id3 ijk(
|
const bool notOnBoundary = boundary.IsRadiusInBoundary(this->NumLayers);
|
||||||
cellIndex % Dims[0], (cellIndex / Dims[0]) % Dims[1], cellIndex / (Dims[0] * Dims[1]));
|
value = (notOnBoundary) ? vtkm::CellClassification::NORMAL : vtkm::CellClassification::GHOST;
|
||||||
|
|
||||||
value = (Range.Contains(ijk) ? NormalCell : DuplicateCell);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vtkm::Id3 Dims;
|
vtkm::IdComponent NumLayers;
|
||||||
vtkm::Id NumLayers;
|
|
||||||
vtkm::RangeId3 Range;
|
|
||||||
static constexpr vtkm::UInt8 NormalCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::NORMAL);
|
|
||||||
static constexpr vtkm::UInt8 DuplicateCell =
|
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::GHOST);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -137,11 +103,8 @@ inline VTKM_CONT vtkm::cont::DataSet GhostCellClassify::DoExecute(const vtkm::co
|
|||||||
vtkm::filter::PolicyBase<Policy>)
|
vtkm::filter::PolicyBase<Policy>)
|
||||||
{
|
{
|
||||||
const vtkm::cont::DynamicCellSet& cellset = input.GetCellSet();
|
const vtkm::cont::DynamicCellSet& cellset = input.GetCellSet();
|
||||||
vtkm::Id numCells = cellset.GetNumberOfCells();
|
|
||||||
vtkm::cont::ArrayHandleIndex indexArray(numCells);
|
|
||||||
vtkm::cont::ArrayHandle<vtkm::UInt8> ghosts;
|
vtkm::cont::ArrayHandle<vtkm::UInt8> ghosts;
|
||||||
|
const vtkm::Id numCells = cellset.GetNumberOfCells();
|
||||||
ghosts.Allocate(numCells);
|
|
||||||
|
|
||||||
//Structured cases are easy...
|
//Structured cases are easy...
|
||||||
if (cellset.template IsType<vtkm::cont::CellSetStructured<1>>())
|
if (cellset.template IsType<vtkm::cont::CellSetStructured<1>>())
|
||||||
@ -150,8 +113,12 @@ inline VTKM_CONT vtkm::cont::DataSet GhostCellClassify::DoExecute(const vtkm::co
|
|||||||
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
||||||
|
|
||||||
vtkm::cont::CellSetStructured<1> cellset1d = cellset.Cast<vtkm::cont::CellSetStructured<1>>();
|
vtkm::cont::CellSetStructured<1> cellset1d = cellset.Cast<vtkm::cont::CellSetStructured<1>>();
|
||||||
SetStructuredGhostCells1D structuredGhosts1D(cellset1d.GetCellDimensions());
|
|
||||||
this->Invoke(structuredGhosts1D, indexArray, ghosts);
|
//We use the dual of the cellset since we are using the PointNeighborhood worklet
|
||||||
|
vtkm::cont::CellSetStructured<3> dual;
|
||||||
|
const auto dim = cellset1d.GetCellDimensions();
|
||||||
|
dual.SetPointDimensions(vtkm::Id3{ dim, 1, 1 });
|
||||||
|
this->Invoke(SetStructuredGhostCells1D{}, dual, ghosts);
|
||||||
}
|
}
|
||||||
else if (cellset.template IsType<vtkm::cont::CellSetStructured<2>>())
|
else if (cellset.template IsType<vtkm::cont::CellSetStructured<2>>())
|
||||||
{
|
{
|
||||||
@ -159,8 +126,12 @@ inline VTKM_CONT vtkm::cont::DataSet GhostCellClassify::DoExecute(const vtkm::co
|
|||||||
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
||||||
|
|
||||||
vtkm::cont::CellSetStructured<2> cellset2d = cellset.Cast<vtkm::cont::CellSetStructured<2>>();
|
vtkm::cont::CellSetStructured<2> cellset2d = cellset.Cast<vtkm::cont::CellSetStructured<2>>();
|
||||||
SetStructuredGhostCells2D structuredGhosts2D(cellset2d.GetCellDimensions());
|
|
||||||
this->Invoke(structuredGhosts2D, indexArray, ghosts);
|
//We use the dual of the cellset since we are using the PointNeighborhood worklet
|
||||||
|
vtkm::cont::CellSetStructured<3> dual;
|
||||||
|
const auto dims = cellset2d.GetCellDimensions();
|
||||||
|
dual.SetPointDimensions(vtkm::Id3{ dims[0], dims[1], 1 });
|
||||||
|
this->Invoke(SetStructuredGhostCells2D{}, dual, ghosts);
|
||||||
}
|
}
|
||||||
else if (cellset.template IsType<vtkm::cont::CellSetStructured<3>>())
|
else if (cellset.template IsType<vtkm::cont::CellSetStructured<3>>())
|
||||||
{
|
{
|
||||||
@ -168,8 +139,11 @@ inline VTKM_CONT vtkm::cont::DataSet GhostCellClassify::DoExecute(const vtkm::co
|
|||||||
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
throw vtkm::cont::ErrorFilterExecution("insufficient number of cells for GhostCellClassify.");
|
||||||
|
|
||||||
vtkm::cont::CellSetStructured<3> cellset3d = cellset.Cast<vtkm::cont::CellSetStructured<3>>();
|
vtkm::cont::CellSetStructured<3> cellset3d = cellset.Cast<vtkm::cont::CellSetStructured<3>>();
|
||||||
SetStructuredGhostCells3D structuredGhosts3D(cellset3d.GetCellDimensions());
|
|
||||||
this->Invoke(structuredGhosts3D, indexArray, ghosts);
|
//We use the dual of the cellset since we are using the PointNeighborhood worklet
|
||||||
|
vtkm::cont::CellSetStructured<3> dual;
|
||||||
|
dual.SetPointDimensions(cellset3d.GetCellDimensions());
|
||||||
|
this->Invoke(SetStructuredGhostCells3D{}, dual, ghosts);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -68,16 +68,17 @@ void TestStructured()
|
|||||||
std::cout << "Testing ghost cells for structured datasets." << std::endl;
|
std::cout << "Testing ghost cells for structured datasets." << std::endl;
|
||||||
|
|
||||||
// specify some 2d tests: {numI, numJ, numK, numGhostLayers}.
|
// specify some 2d tests: {numI, numJ, numK, numGhostLayers}.
|
||||||
|
std::vector<std::vector<vtkm::Id>> tests1D = {
|
||||||
|
{ 8, 0, 0, 1 }, { 5, 0, 0, 1 }, { 10, 0, 0, 1 }, { 20, 0, 0, 1 }
|
||||||
|
};
|
||||||
std::vector<std::vector<vtkm::Id>> tests2D = { { 8, 4, 0, 1 }, { 5, 5, 0, 1 }, { 10, 10, 0, 1 },
|
std::vector<std::vector<vtkm::Id>> tests2D = { { 8, 4, 0, 1 }, { 5, 5, 0, 1 }, { 10, 10, 0, 1 },
|
||||||
{ 10, 5, 0, 1 }, { 5, 10, 0, 1 }, { 20, 10, 0, 1 },
|
{ 10, 5, 0, 1 }, { 5, 10, 0, 1 }, { 20, 10, 0, 1 },
|
||||||
{ 10, 20, 0, 1 } };
|
{ 10, 20, 0, 1 } };
|
||||||
std::vector<std::vector<vtkm::Id>> tests3D = { { 8, 8, 10, 1 }, { 5, 5, 5, 1 },
|
std::vector<std::vector<vtkm::Id>> tests3D = { { 8, 8, 10, 1 }, { 5, 5, 5, 1 },
|
||||||
{ 10, 10, 10, 1 }, { 10, 5, 10, 1 },
|
{ 10, 10, 10, 1 }, { 10, 5, 10, 1 },
|
||||||
{ 5, 10, 10, 1 }, { 20, 10, 10, 1 },
|
{ 5, 10, 10, 1 }, { 20, 10, 10, 1 },
|
||||||
{ 10, 20, 10, 1 } };
|
{ 10, 20, 10, 1 }, { 1024, 512, 512, 1 },
|
||||||
std::vector<std::vector<vtkm::Id>> tests1D = {
|
{ 1024, 768, 10, 1 } };
|
||||||
{ 8, 0, 0, 1 }, { 5, 0, 0, 1 }, { 10, 0, 0, 1 }, { 20, 0, 0, 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::vector<vtkm::Id>> tests;
|
std::vector<std::vector<vtkm::Id>> tests;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ void TestStructured()
|
|||||||
|
|
||||||
vtkm::Id numNormalCells = 0;
|
vtkm::Id numNormalCells = 0;
|
||||||
auto portal = ghostArray.GetPortalConstControl();
|
auto portal = ghostArray.GetPortalConstControl();
|
||||||
const vtkm::UInt8 normalCell = static_cast<vtkm::UInt8>(vtkm::CellClassification::NORMAL);
|
constexpr vtkm::UInt8 normalCell = vtkm::CellClassification::NORMAL;
|
||||||
for (vtkm::Id i = 0; i < numCells; i++)
|
for (vtkm::Id i = 0; i < numCells; i++)
|
||||||
if (portal.Get(i) == normalCell)
|
if (portal.Get(i) == normalCell)
|
||||||
numNormalCells++;
|
numNormalCells++;
|
||||||
|
@ -33,8 +33,8 @@ static vtkm::cont::ArrayHandle<vtkm::UInt8> StructuredGhostCellArray(vtkm::Id nx
|
|||||||
if (nz > 0)
|
if (nz > 0)
|
||||||
numCells *= nz;
|
numCells *= nz;
|
||||||
|
|
||||||
vtkm::UInt8 normalCell = static_cast<vtkm::UInt8>(vtkm::CellClassification::NORMAL);
|
constexpr vtkm::UInt8 normalCell = vtkm::CellClassification::NORMAL;
|
||||||
vtkm::UInt8 duplicateCell = static_cast<vtkm::UInt8>(vtkm::CellClassification::GHOST);
|
constexpr vtkm::UInt8 duplicateCell = vtkm::CellClassification::GHOST;
|
||||||
|
|
||||||
vtkm::cont::ArrayHandle<vtkm::UInt8> ghosts;
|
vtkm::cont::ArrayHandle<vtkm::UInt8> ghosts;
|
||||||
ghosts.Allocate(numCells);
|
ghosts.Allocate(numCells);
|
||||||
@ -261,10 +261,9 @@ void TestGhostCellRemove()
|
|||||||
if (rt == "all")
|
if (rt == "all")
|
||||||
ghostCellRemoval.RemoveAllGhost();
|
ghostCellRemoval.RemoveAllGhost();
|
||||||
else if (rt == "byType")
|
else if (rt == "byType")
|
||||||
ghostCellRemoval.RemoveByType(
|
ghostCellRemoval.RemoveByType(vtkm::CellClassification::GHOST);
|
||||||
static_cast<vtkm::UInt8>(vtkm::CellClassification::GHOST));
|
|
||||||
|
|
||||||
auto output = ghostCellRemoval.Execute(ds, vtkm::filter::GhostCellRemovePolicy());
|
auto output = ghostCellRemoval.Execute(ds);
|
||||||
vtkm::Id numCells = output.GetNumberOfCells();
|
vtkm::Id numCells = output.GetNumberOfCells();
|
||||||
|
|
||||||
//Validate the output.
|
//Validate the output.
|
||||||
@ -305,7 +304,7 @@ void TestGhostCellRemove()
|
|||||||
|
|
||||||
vtkm::filter::GhostCellRemove ghostCellRemoval;
|
vtkm::filter::GhostCellRemove ghostCellRemoval;
|
||||||
ghostCellRemoval.RemoveGhostField();
|
ghostCellRemoval.RemoveGhostField();
|
||||||
auto output = ghostCellRemoval.Execute(ds, vtkm::filter::GhostCellRemovePolicy());
|
auto output = ghostCellRemoval.Execute(ds);
|
||||||
VTKM_TEST_ASSERT(output.GetCellSet().IsType<vtkm::cont::CellSetExplicit<>>(),
|
VTKM_TEST_ASSERT(output.GetCellSet().IsType<vtkm::cont::CellSetExplicit<>>(),
|
||||||
"Wrong cell type for explicit conversion");
|
"Wrong cell type for explicit conversion");
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
// PURPOSE. See the above copyright notice for more information.
|
// PURPOSE. See the above copyright notice for more information.
|
||||||
//============================================================================
|
//============================================================================
|
||||||
#ifndef vtk_m_worklet_WorkletPointNeigborhood_h
|
#ifndef vtk_m_worklet_WorkletPointNeighborhood_h
|
||||||
#define vtk_m_worklet_WorkletPointNeigborhood_h
|
#define vtk_m_worklet_WorkletPointNeighborhood_h
|
||||||
|
|
||||||
/// \brief Worklet for volume algorithms that require a neighborhood
|
/// \brief Worklet for volume algorithms that require a neighborhood
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user