mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Support for dist-memory pathlines.
This commit is contained in:
parent
5b9eb1ceb0
commit
aa713b565f
@ -31,6 +31,17 @@ VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos,
|
||||
bool CopyTerminatedOnly = false);
|
||||
|
||||
|
||||
/// \brief Copy fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given a std::vector of \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
/// position field into an \c ArrayHandle of \c Vec3f objects.
|
||||
///
|
||||
template <typename ParticleType>
|
||||
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
|
||||
const std::vector<vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>>& inputs,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos);
|
||||
|
||||
/// \brief Copy all fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
|
@ -87,6 +87,29 @@ VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
|
||||
vtkm::cont::ArrayCopy(posTrn, outPos);
|
||||
}
|
||||
|
||||
|
||||
template <typename ParticleType>
|
||||
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
|
||||
const std::vector<vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>>& inputs,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos)
|
||||
{
|
||||
vtkm::Id numParticles = 0;
|
||||
for (const auto& v : inputs)
|
||||
numParticles += v.GetNumberOfValues();
|
||||
outPos.Allocate(numParticles);
|
||||
|
||||
vtkm::Id idx = 0;
|
||||
for (const auto& v : inputs)
|
||||
{
|
||||
auto posTrn =
|
||||
vtkm::cont::make_ArrayHandleTransform(v, detail::ExtractPositionFunctor<ParticleType>());
|
||||
vtkm::Id n = posTrn.GetNumberOfValues();
|
||||
vtkm::cont::Algorithm::CopySubRange(posTrn, 0, n, outPos, idx);
|
||||
idx += n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// \brief Copy all fields in vtkm::Particle to standard types.
|
||||
///
|
||||
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
|
||||
|
@ -29,7 +29,7 @@ void TestParticleArrayCopy()
|
||||
particles.push_back(vtkm::Particle(vtkm::Vec3f(x, y, z), i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (vtkm::Id i = 0; i < 2; i++)
|
||||
{
|
||||
auto particleAH = vtkm::cont::make_ArrayHandle(particles, vtkm::CopyFlag::Off);
|
||||
|
||||
@ -64,11 +64,51 @@ void TestParticleArrayCopy()
|
||||
VTKM_TEST_ASSERT(p.Pos == pt, "Positions do not match");
|
||||
VTKM_TEST_ASSERT(p.ID == ids.ReadPortal().Get(j), "IDs do not match");
|
||||
VTKM_TEST_ASSERT(p.NumSteps == steps.ReadPortal().Get(j), "Steps do not match");
|
||||
VTKM_TEST_ASSERT(p.Status == status.ReadPortal().Get(j), "Steps do not match");
|
||||
VTKM_TEST_ASSERT(p.Status == status.ReadPortal().Get(j), "Status do not match");
|
||||
VTKM_TEST_ASSERT(p.Time == ptime.ReadPortal().Get(j), "Times do not match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Test copying a vector of ArrayHandles.
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::Particle>> particleVec;
|
||||
vtkm::Id totalNumParticles = 0;
|
||||
vtkm::Id pid = 0;
|
||||
for (vtkm::Id i = 0; i < 4; i++)
|
||||
{
|
||||
vtkm::Id n = 5 + i;
|
||||
std::vector<vtkm::Particle> vec;
|
||||
for (vtkm::Id j = 0; j < n; j++)
|
||||
{
|
||||
auto x = dist(generator);
|
||||
auto y = dist(generator);
|
||||
auto z = dist(generator);
|
||||
vec.push_back(vtkm::Particle(vtkm::Vec3f(x, y, z), pid));
|
||||
pid++;
|
||||
}
|
||||
auto ah = vtkm::cont::make_ArrayHandle(vec, vtkm::CopyFlag::Off);
|
||||
particleVec.push_back(ah);
|
||||
totalNumParticles += ah.GetNumberOfValues();
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> res;
|
||||
vtkm::cont::ParticleArrayCopy<vtkm::Particle>(particleVec, res);
|
||||
VTKM_TEST_ASSERT(res.GetNumberOfValues() == totalNumParticles, "Wrong number of particles");
|
||||
|
||||
vtkm::Id resIdx = 0;
|
||||
auto resPortal = res.ReadPortal();
|
||||
for (const auto& v : particleVec)
|
||||
{
|
||||
vtkm::Id n = v.GetNumberOfValues();
|
||||
auto portal = v.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < n; i++)
|
||||
{
|
||||
auto p = portal.Get(i);
|
||||
auto pRes = resPortal.Get(resIdx);
|
||||
VTKM_TEST_ASSERT(p.Pos == pRes, "Positions do not match");
|
||||
resIdx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UnitTestParticleArrayCopy(int argc, char* argv[])
|
||||
|
@ -46,28 +46,33 @@ inline VTKM_CONT vtkm::cont::PartitionedDataSet ParticleAdvection::PrepareForExe
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
||||
{
|
||||
if (this->GetUseCoordinateSystemAsField())
|
||||
throw vtkm::cont::ErrorFilterExecution("Coordinate system as field not supported");
|
||||
if (this->Seeds.GetNumberOfValues() == 0)
|
||||
throw vtkm::cont::ErrorFilterExecution("No seeds provided.");
|
||||
|
||||
std::string activeField = this->GetActiveFieldName();
|
||||
vtkm::filter::particleadvection::BoundsMap boundsMap(input);
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
std::vector<DataSetIntegratorType> dsi;
|
||||
using DSIType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
std::vector<DSIType> dsi;
|
||||
|
||||
for (vtkm::Id i = 0; i < input.GetNumberOfPartitions(); i++)
|
||||
{
|
||||
vtkm::Id blockId = boundsMap.GetLocalBlockId(i);
|
||||
dsi.push_back(DataSetIntegratorType(input.GetPartition(i), blockId, activeField));
|
||||
auto ds = input.GetPartition(i);
|
||||
if (!ds.HasPointField(activeField))
|
||||
throw vtkm::cont::ErrorFilterExecution("Unsupported field assocation");
|
||||
dsi.push_back(DSIType(ds, blockId, activeField));
|
||||
}
|
||||
|
||||
using AlgorithmType = vtkm::filter::particleadvection::ParticleAdvectionAlgorithm;
|
||||
using ThreadedAlgorithmType = vtkm::filter::particleadvection::ParticleAdvectionThreadedAlgorithm;
|
||||
|
||||
if (this->UseThreadedAlgorithm)
|
||||
return vtkm::filter::particleadvection::RunAlgo<ThreadedAlgorithmType>(
|
||||
if (this->GetUseThreadedAlgorithm())
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, ThreadedAlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
else
|
||||
return vtkm::filter::particleadvection::RunAlgo<AlgorithmType>(
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, AlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,14 @@ public:
|
||||
void SetNextTime(vtkm::FloatDefault t) { this->NextTime = t; }
|
||||
|
||||
VTKM_CONT
|
||||
void SetNextDataSet(const vtkm::cont::DataSet& ds) { this->NextDataSet = ds; }
|
||||
void SetNextDataSet(const vtkm::cont::DataSet& ds)
|
||||
{
|
||||
this->NextDataSet = vtkm::cont::PartitionedDataSet(ds);
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void SetNextDataSet(const vtkm::cont::PartitionedDataSet& pds) { this->NextDataSet = pds; }
|
||||
|
||||
|
||||
VTKM_CONT
|
||||
void SetStepSize(vtkm::FloatDefault s) { this->StepSize = s; }
|
||||
@ -49,11 +56,15 @@ public:
|
||||
VTKM_CONT
|
||||
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds);
|
||||
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
VTKM_CONT vtkm::cont::DataSet DoExecute(
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
VTKM_CONT
|
||||
bool GetUseThreadedAlgorithm() { return this->UseThreadedAlgorithm; }
|
||||
|
||||
VTKM_CONT
|
||||
void SetUseThreadedAlgorithm(bool val) { this->UseThreadedAlgorithm = val; }
|
||||
|
||||
template <typename DerivedPolicy>
|
||||
vtkm::cont::PartitionedDataSet PrepareForExecution(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
|
||||
|
||||
template <typename DerivedPolicy>
|
||||
@ -62,13 +73,13 @@ public:
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy);
|
||||
|
||||
private:
|
||||
vtkm::worklet::Streamline Worklet;
|
||||
vtkm::FloatDefault StepSize;
|
||||
vtkm::FloatDefault PreviousTime;
|
||||
vtkm::FloatDefault NextTime;
|
||||
vtkm::cont::DataSet NextDataSet;
|
||||
vtkm::cont::PartitionedDataSet NextDataSet;
|
||||
vtkm::Id NumberOfSteps;
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
|
||||
bool UseThreadedAlgorithm;
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::filter
|
||||
|
@ -11,15 +11,14 @@
|
||||
#ifndef vtk_m_filter_Pathline_hxx
|
||||
#define vtk_m_filter_Pathline_hxx
|
||||
|
||||
#include <vtkm/filter/Pathline.h>
|
||||
|
||||
#include <vtkm/cont/ArrayCopy.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ErrorFilterExecution.h>
|
||||
#include <vtkm/worklet/particleadvection/Field.h>
|
||||
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
|
||||
#include <vtkm/worklet/particleadvection/IntegratorBase.h>
|
||||
#include <vtkm/worklet/particleadvection/Particles.h>
|
||||
#include <vtkm/worklet/particleadvection/RK4Integrator.h>
|
||||
#include <vtkm/worklet/particleadvection/TemporalGridEvaluators.h>
|
||||
#include <vtkm/filter/particleadvection/BoundsMap.h>
|
||||
#include <vtkm/filter/particleadvection/DataSetIntegrator.h>
|
||||
#include <vtkm/filter/particleadvection/StreamlineAlgorithm.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -29,7 +28,7 @@ namespace filter
|
||||
//-----------------------------------------------------------------------------
|
||||
inline VTKM_CONT Pathline::Pathline()
|
||||
: vtkm::filter::FilterDataSetWithField<Pathline>()
|
||||
, Worklet()
|
||||
, UseThreadedAlgorithm(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -40,58 +39,50 @@ inline VTKM_CONT void Pathline::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
inline VTKM_CONT vtkm::cont::DataSet Pathline::DoExecute(
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
template <typename DerivedPolicy>
|
||||
inline VTKM_CONT vtkm::cont::PartitionedDataSet Pathline::PrepareForExecution(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
||||
{
|
||||
//Check for some basics.
|
||||
if (this->GetUseCoordinateSystemAsField())
|
||||
throw vtkm::cont::ErrorFilterExecution("Coordinate system as field not supported");
|
||||
if (this->Seeds.GetNumberOfValues() == 0)
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution("No seeds provided.");
|
||||
}
|
||||
|
||||
const vtkm::cont::DynamicCellSet& cells = input.GetCellSet();
|
||||
const vtkm::cont::DynamicCellSet& cells2 = this->NextDataSet.GetCellSet();
|
||||
const vtkm::cont::CoordinateSystem& coords =
|
||||
input.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex());
|
||||
const vtkm::cont::CoordinateSystem& coords2 =
|
||||
this->NextDataSet.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex());
|
||||
if (this->NextDataSet.GetNumberOfPartitions() != input.GetNumberOfPartitions())
|
||||
throw vtkm::cont::ErrorFilterExecution("Number of partitions do not match");
|
||||
|
||||
auto field2 = vtkm::cont::Cast<vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>>(
|
||||
this->NextDataSet.GetField(this->GetActiveFieldName()).GetData());
|
||||
if (!(this->PreviousTime < this->NextTime))
|
||||
throw vtkm::cont::ErrorFilterExecution("Previous time must be less than Next time.");
|
||||
|
||||
if (!fieldMeta.IsPointField())
|
||||
if (this->NextDataSet.GetNumberOfPartitions() == 0)
|
||||
return vtkm::cont::PartitionedDataSet();
|
||||
|
||||
std::string activeField = this->GetActiveFieldName();
|
||||
vtkm::filter::particleadvection::BoundsMap boundsMap(input);
|
||||
using DSIType = vtkm::filter::particleadvection::TemporalDataSetIntegrator;
|
||||
std::vector<DSIType> dsi;
|
||||
|
||||
for (vtkm::Id i = 0; i < input.GetNumberOfPartitions(); i++)
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution("Point field expected.");
|
||||
vtkm::Id blockId = boundsMap.GetLocalBlockId(i);
|
||||
auto dsPrev = input.GetPartition(i);
|
||||
auto dsNext = this->NextDataSet.GetPartition(i);
|
||||
if (!dsPrev.HasPointField(activeField) || !dsNext.HasPointField(activeField))
|
||||
throw vtkm::cont::ErrorFilterExecution("Unsupported field assocation");
|
||||
dsi.push_back(
|
||||
DSIType(dsPrev, this->PreviousTime, dsNext, this->NextTime, blockId, activeField));
|
||||
}
|
||||
|
||||
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
|
||||
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
|
||||
using GridEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<FieldType>;
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
using AlgorithmType = vtkm::filter::particleadvection::PathlineAlgorithm;
|
||||
using ThreadedAlgorithmType = vtkm::filter::particleadvection::PathlineThreadedAlgorithm;
|
||||
|
||||
FieldType velocities(field);
|
||||
FieldType velocities2(field2);
|
||||
GridEvalType eval(
|
||||
coords, cells, velocities, this->PreviousTime, coords2, cells2, velocities2, this->NextTime);
|
||||
RK4Type rk4(eval, this->StepSize);
|
||||
|
||||
vtkm::worklet::Streamline streamline;
|
||||
vtkm::worklet::StreamlineResult<vtkm::Particle> res;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
|
||||
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
|
||||
res = Worklet.Run(rk4, seedArray, this->NumberOfSteps);
|
||||
|
||||
vtkm::cont::DataSet outData;
|
||||
vtkm::cont::CoordinateSystem outputCoords("coordinates", res.Positions);
|
||||
outData.SetCellSet(res.PolyLines);
|
||||
outData.AddCoordinateSystem(outputCoords);
|
||||
|
||||
return outData;
|
||||
if (this->GetUseThreadedAlgorithm())
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, ThreadedAlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
else
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, AlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -45,28 +45,33 @@ inline VTKM_CONT vtkm::cont::PartitionedDataSet Streamline::PrepareForExecution(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
||||
{
|
||||
if (this->GetUseCoordinateSystemAsField())
|
||||
throw vtkm::cont::ErrorFilterExecution("Coordinate system as field not supported");
|
||||
if (this->Seeds.GetNumberOfValues() == 0)
|
||||
throw vtkm::cont::ErrorFilterExecution("No seeds provided.");
|
||||
|
||||
std::string activeField = this->GetActiveFieldName();
|
||||
vtkm::filter::particleadvection::BoundsMap boundsMap(input);
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
std::vector<DataSetIntegratorType> dsi;
|
||||
using DSIType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
std::vector<DSIType> dsi;
|
||||
|
||||
for (vtkm::Id i = 0; i < input.GetNumberOfPartitions(); i++)
|
||||
{
|
||||
vtkm::Id blockId = boundsMap.GetLocalBlockId(i);
|
||||
dsi.push_back(DataSetIntegratorType(input.GetPartition(i), blockId, activeField));
|
||||
auto ds = input.GetPartition(i);
|
||||
if (!ds.HasPointField(activeField))
|
||||
throw vtkm::cont::ErrorFilterExecution("Unsupported field assocation");
|
||||
dsi.push_back(DSIType(ds, blockId, activeField));
|
||||
}
|
||||
|
||||
using AlgorithmType = vtkm::filter::particleadvection::StreamlineAlgorithm;
|
||||
using ThreadedAlgorithmType = vtkm::filter::particleadvection::StreamlineThreadedAlgorithm;
|
||||
|
||||
if (this->UseThreadedAlgorithm)
|
||||
return vtkm::filter::particleadvection::RunAlgo<ThreadedAlgorithmType>(
|
||||
if (this->GetUseThreadedAlgorithm())
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, ThreadedAlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
else
|
||||
return vtkm::filter::particleadvection::RunAlgo<AlgorithmType>(
|
||||
return vtkm::filter::particleadvection::RunAlgo<DSIType, AlgorithmType>(
|
||||
boundsMap, dsi, this->NumberOfSteps, this->StepSize, this->Seeds);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,10 @@
|
||||
#ifndef vtk_m_filter_particleadvection_AdvectorBaseAlgorithm_h
|
||||
#define vtk_m_filter_particleadvection_AdvectorBaseAlgorithm_h
|
||||
|
||||
#include <vtkm/cont/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayHandlePermutation.h>
|
||||
#include <vtkm/cont/ErrorFilterExecution.h>
|
||||
#include <vtkm/cont/ParticleArrayCopy.h>
|
||||
#include <vtkm/filter/particleadvection/DataSetIntegrator.h>
|
||||
#include <vtkm/filter/particleadvection/ParticleMessenger.h>
|
||||
|
||||
@ -24,9 +27,183 @@ namespace filter
|
||||
{
|
||||
namespace particleadvection
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
template <typename AlgorithmType>
|
||||
namespace internal
|
||||
{
|
||||
|
||||
//Helper class to store the different result types.
|
||||
template <typename ResultType>
|
||||
class ResultHelper;
|
||||
|
||||
//Specialization for ParticleAdvectionResult
|
||||
using PAType = vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>;
|
||||
|
||||
template <>
|
||||
class ResultHelper<PAType>
|
||||
{
|
||||
public:
|
||||
static void Store(std::map<vtkm::Id, std::vector<PAType>>& results,
|
||||
const PAType& res,
|
||||
vtkm::Id blockId,
|
||||
const std::vector<vtkm::Id>& indices)
|
||||
{
|
||||
if (indices.empty())
|
||||
return;
|
||||
|
||||
//Selected out the terminated particles and store them.
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> termParticles;
|
||||
auto indicesAH = vtkm::cont::make_ArrayHandle(indices, vtkm::CopyFlag::Off);
|
||||
auto perm = vtkm::cont::make_ArrayHandlePermutation(indicesAH, res.Particles);
|
||||
|
||||
vtkm::cont::Algorithm::Copy(perm, termParticles);
|
||||
PAType termRes(termParticles);
|
||||
results[blockId].push_back(termRes);
|
||||
}
|
||||
|
||||
static vtkm::cont::PartitionedDataSet GetOutput(
|
||||
const std::map<vtkm::Id, std::vector<PAType>>& results)
|
||||
{
|
||||
vtkm::cont::PartitionedDataSet output;
|
||||
for (const auto& it : results)
|
||||
{
|
||||
std::size_t nResults = it.second.size();
|
||||
if (nResults == 0)
|
||||
continue;
|
||||
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::Particle>> allParticles;
|
||||
allParticles.reserve(static_cast<std::size_t>(nResults));
|
||||
|
||||
for (const auto& res : it.second)
|
||||
allParticles.push_back(res.Particles);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> pts;
|
||||
vtkm::cont::ParticleArrayCopy(allParticles, pts);
|
||||
|
||||
vtkm::cont::DataSet ds;
|
||||
vtkm::cont::CoordinateSystem outCoords("coordinates", pts);
|
||||
ds.AddCoordinateSystem(outCoords);
|
||||
|
||||
//Create vertex cell set
|
||||
vtkm::Id numPoints = pts.GetNumberOfValues();
|
||||
vtkm::cont::CellSetSingleType<> cells;
|
||||
vtkm::cont::ArrayHandleIndex conn(numPoints);
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
||||
|
||||
vtkm::cont::ArrayCopy(conn, connectivity);
|
||||
cells.Fill(numPoints, vtkm::CELL_SHAPE_VERTEX, 1, connectivity);
|
||||
ds.SetCellSet(cells);
|
||||
|
||||
output.AppendPartition(ds);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
//Specialization for StreamlineResult
|
||||
using SLType = vtkm::worklet::StreamlineResult<vtkm::Particle>;
|
||||
|
||||
template <>
|
||||
class ResultHelper<SLType>
|
||||
{
|
||||
public:
|
||||
static void Store(std::map<vtkm::Id, std::vector<SLType>>& results,
|
||||
const SLType& res,
|
||||
vtkm::Id blockId,
|
||||
const std::vector<vtkm::Id>& vtkmNotUsed(indices))
|
||||
{
|
||||
results[blockId].push_back(res);
|
||||
}
|
||||
|
||||
static vtkm::cont::PartitionedDataSet GetOutput(
|
||||
const std::map<vtkm::Id, std::vector<SLType>>& results)
|
||||
{
|
||||
vtkm::cont::PartitionedDataSet output;
|
||||
for (const auto& it : results)
|
||||
{
|
||||
std::size_t nResults = it.second.size();
|
||||
if (nResults == 0)
|
||||
continue;
|
||||
|
||||
vtkm::cont::DataSet ds;
|
||||
//Easy case with one result.
|
||||
if (nResults == 1)
|
||||
{
|
||||
ds.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", it.second[0].Positions));
|
||||
ds.SetCellSet(it.second[0].PolyLines);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Append all the results into one data set.
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> appendPts;
|
||||
std::vector<vtkm::Id> posOffsets(nResults);
|
||||
|
||||
const auto& res0 = it.second[0];
|
||||
vtkm::Id totalNumCells = res0.PolyLines.GetNumberOfCells();
|
||||
vtkm::Id totalNumPts = res0.Positions.GetNumberOfValues();
|
||||
|
||||
posOffsets[0] = 0;
|
||||
for (std::size_t i = 1; i < nResults; i++)
|
||||
{
|
||||
const auto& res = it.second[i];
|
||||
posOffsets[i] = totalNumPts;
|
||||
totalNumPts += res.Positions.GetNumberOfValues();
|
||||
totalNumCells += res.PolyLines.GetNumberOfCells();
|
||||
}
|
||||
|
||||
//Append all the points together.
|
||||
appendPts.Allocate(totalNumPts);
|
||||
for (std::size_t i = 0; i < nResults; i++)
|
||||
{
|
||||
const auto& res = it.second[i];
|
||||
// copy all values into appendPts starting at offset.
|
||||
vtkm::cont::Algorithm::CopySubRange(
|
||||
res.Positions, 0, res.Positions.GetNumberOfValues(), appendPts, posOffsets[i]);
|
||||
}
|
||||
vtkm::cont::CoordinateSystem outputCoords =
|
||||
vtkm::cont::CoordinateSystem("coordinates", appendPts);
|
||||
ds.AddCoordinateSystem(outputCoords);
|
||||
|
||||
//Create polylines.
|
||||
std::vector<vtkm::Id> numPtsPerCell(static_cast<std::size_t>(totalNumCells));
|
||||
std::size_t off = 0;
|
||||
for (std::size_t i = 0; i < nResults; i++)
|
||||
{
|
||||
const auto& res = it.second[i];
|
||||
vtkm::Id nCells = res.PolyLines.GetNumberOfCells();
|
||||
for (vtkm::Id j = 0; j < nCells; j++)
|
||||
numPtsPerCell[off++] = static_cast<vtkm::Id>(res.PolyLines.GetNumberOfPointsInCell(j));
|
||||
}
|
||||
|
||||
auto numPointsPerCellArray =
|
||||
vtkm::cont::make_ArrayHandle(numPtsPerCell, vtkm::CopyFlag::Off);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> cellIndex;
|
||||
vtkm::Id connectivityLen =
|
||||
vtkm::cont::Algorithm::ScanExclusive(numPointsPerCellArray, cellIndex);
|
||||
vtkm::cont::ArrayHandleIndex connCount(connectivityLen);
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
||||
vtkm::cont::ArrayCopy(connCount, connectivity);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> cellTypes;
|
||||
auto polyLineShape = vtkm::cont::make_ArrayHandleConstant<vtkm::UInt8>(
|
||||
vtkm::CELL_SHAPE_POLY_LINE, totalNumCells);
|
||||
vtkm::cont::ArrayCopy(polyLineShape, cellTypes);
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numPointsPerCellArray);
|
||||
|
||||
vtkm::cont::CellSetExplicit<> polyLines;
|
||||
polyLines.Fill(totalNumPts, cellTypes, connectivity, offsets);
|
||||
ds.SetCellSet(polyLines);
|
||||
}
|
||||
output.AppendPartition(ds);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename DataSetIntegratorType, typename AlgorithmType>
|
||||
vtkm::cont::PartitionedDataSet RunAlgo(const vtkm::filter::particleadvection::BoundsMap& boundsMap,
|
||||
const std::vector<DataSetIntegratorType>& dsi,
|
||||
vtkm::Id numSteps,
|
||||
@ -45,11 +222,9 @@ vtkm::cont::PartitionedDataSet RunAlgo(const vtkm::filter::particleadvection::Bo
|
||||
//
|
||||
// Base class for particle advector
|
||||
//
|
||||
template <typename ResultType>
|
||||
template <typename DataSetIntegratorType, typename ResultType>
|
||||
class VTKM_ALWAYS_EXPORT AdvectorBaseAlgorithm
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
public:
|
||||
AdvectorBaseAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
@ -107,7 +282,6 @@ public:
|
||||
if (GetActiveParticles(v, blockId))
|
||||
{
|
||||
const auto& block = this->GetDataSet(blockId);
|
||||
|
||||
ResultType r;
|
||||
block.Advect(v, this->StepSize, this->NumberOfSteps, r);
|
||||
numTerm = this->UpdateResult(r, blockId);
|
||||
@ -122,14 +296,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline vtkm::cont::PartitionedDataSet GetOutput();
|
||||
vtkm::cont::PartitionedDataSet GetOutput() const
|
||||
{
|
||||
return internal::ResultHelper<ResultType>::GetOutput(this->Results);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ClearParticles()
|
||||
{
|
||||
this->Active.clear();
|
||||
this->Inactive.clear();
|
||||
this->Terminated.clear();
|
||||
this->ParticleBlockIDsMap.clear();
|
||||
}
|
||||
|
||||
@ -151,69 +327,6 @@ protected:
|
||||
throw vtkm::cont::ErrorFilterExecution("Bad block");
|
||||
}
|
||||
|
||||
void UpdateResultParticle(vtkm::Particle& p,
|
||||
std::vector<vtkm::Particle>& I,
|
||||
std::vector<vtkm::Particle>& T,
|
||||
std::vector<vtkm::Particle>& A,
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMapI,
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMapA) const
|
||||
{
|
||||
if (p.Status.CheckTerminate())
|
||||
T.push_back(p);
|
||||
else
|
||||
{
|
||||
const auto& it = this->ParticleBlockIDsMap.find(p.ID);
|
||||
VTKM_ASSERT(it != this->ParticleBlockIDsMap.end());
|
||||
auto currBIDs = it->second;
|
||||
VTKM_ASSERT(!currBIDs.empty());
|
||||
|
||||
std::vector<vtkm::Id> newIDs;
|
||||
if (p.Status.CheckSpatialBounds() && !p.Status.CheckTookAnySteps())
|
||||
newIDs.assign(std::next(currBIDs.begin(), 1), currBIDs.end());
|
||||
else
|
||||
newIDs = this->BoundsMap.FindBlocks(p.Pos, currBIDs);
|
||||
|
||||
//reset the particle status.
|
||||
p.Status = vtkm::ParticleStatus();
|
||||
|
||||
if (newIDs.empty()) //No blocks, we're done.
|
||||
{
|
||||
p.Status.SetTerminate();
|
||||
T.push_back(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we have more than blockId, we want to minimize communication
|
||||
//and put any blocks owned by this rank first.
|
||||
if (newIDs.size() > 1)
|
||||
{
|
||||
for (auto idit = newIDs.begin(); idit != newIDs.end(); idit++)
|
||||
{
|
||||
vtkm::Id bid = *idit;
|
||||
if (this->BoundsMap.FindRank(bid) == this->Rank)
|
||||
{
|
||||
newIDs.erase(idit);
|
||||
newIDs.insert(newIDs.begin(), bid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dstRank = this->BoundsMap.FindRank(newIDs[0]);
|
||||
if (dstRank == this->Rank)
|
||||
{
|
||||
A.push_back(p);
|
||||
idsMapA[p.ID] = newIDs;
|
||||
}
|
||||
else
|
||||
{
|
||||
I.push_back(p);
|
||||
idsMapI[p.ID] = newIDs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetSeedArray(const std::vector<vtkm::Particle>& particles,
|
||||
const std::vector<std::vector<vtkm::Id>>& blockIds)
|
||||
{
|
||||
@ -277,58 +390,133 @@ protected:
|
||||
virtual void UpdateActive(const std::vector<vtkm::Particle>& particles,
|
||||
const std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMap)
|
||||
{
|
||||
VTKM_ASSERT(particles.size() == idsMap.size());
|
||||
if (particles.empty())
|
||||
return;
|
||||
|
||||
this->Active.insert(this->Active.end(), particles.begin(), particles.end());
|
||||
for (const auto& it : idsMap)
|
||||
this->ParticleBlockIDsMap[it.first] = it.second;
|
||||
this->Update(this->Active, particles, idsMap);
|
||||
}
|
||||
|
||||
virtual void UpdateInactive(const std::vector<vtkm::Particle>& particles,
|
||||
const std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMap)
|
||||
{
|
||||
VTKM_ASSERT(particles.size() == idsMap.size());
|
||||
if (particles.empty())
|
||||
return;
|
||||
this->Update(this->Inactive, particles, idsMap);
|
||||
}
|
||||
|
||||
this->Inactive.insert(this->Inactive.end(), particles.begin(), particles.end());
|
||||
void Update(std::vector<vtkm::Particle>& arr,
|
||||
const std::vector<vtkm::Particle>& particles,
|
||||
const std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMap)
|
||||
{
|
||||
VTKM_ASSERT(particles.size() == idsMap.size());
|
||||
|
||||
arr.insert(arr.end(), particles.begin(), particles.end());
|
||||
for (const auto& it : idsMap)
|
||||
this->ParticleBlockIDsMap[it.first] = it.second;
|
||||
}
|
||||
|
||||
virtual void UpdateTerminated(const std::vector<vtkm::Particle>& particles, vtkm::Id blockId)
|
||||
void UpdateTerminated(const vtkm::cont::ArrayHandle<vtkm::Particle>& particles,
|
||||
const std::vector<vtkm::Id>& idxTerm)
|
||||
{
|
||||
if (particles.empty())
|
||||
return;
|
||||
|
||||
for (const auto& t : particles)
|
||||
this->ParticleBlockIDsMap.erase(t.ID);
|
||||
auto& it = this->Terminated[blockId];
|
||||
it.insert(it.end(), particles.begin(), particles.end());
|
||||
auto portal = particles.ReadPortal();
|
||||
for (const auto& idx : idxTerm)
|
||||
this->ParticleBlockIDsMap.erase(portal.Get(idx).ID);
|
||||
}
|
||||
|
||||
vtkm::Id UpdateResult(const ResultType& res, vtkm::Id blockId)
|
||||
void ClassifyParticles(const vtkm::cont::ArrayHandle<vtkm::Particle>& particles,
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMapA,
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>>& idsMapI,
|
||||
std::vector<vtkm::Particle>& A,
|
||||
std::vector<vtkm::Particle>& I,
|
||||
std::vector<vtkm::Id>& termIdx) const
|
||||
{
|
||||
vtkm::Id n = res.Particles.GetNumberOfValues();
|
||||
auto portal = res.Particles.ReadPortal();
|
||||
A.clear();
|
||||
I.clear();
|
||||
termIdx.clear();
|
||||
idsMapI.clear();
|
||||
idsMapA.clear();
|
||||
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>> idsMapI, idsMapA;
|
||||
std::vector<vtkm::Particle> I, T, A;
|
||||
auto portal = particles.WritePortal();
|
||||
vtkm::Id n = portal.GetNumberOfValues();
|
||||
|
||||
for (vtkm::Id i = 0; i < n; i++)
|
||||
{
|
||||
vtkm::Particle p = portal.Get(i);
|
||||
this->UpdateResultParticle(p, I, T, A, idsMapI, idsMapA);
|
||||
auto p = portal.Get(i);
|
||||
|
||||
if (p.Status.CheckTerminate())
|
||||
termIdx.push_back(i);
|
||||
else
|
||||
{
|
||||
const auto& it = this->ParticleBlockIDsMap.find(p.ID);
|
||||
VTKM_ASSERT(it != this->ParticleBlockIDsMap.end());
|
||||
auto currBIDs = it->second;
|
||||
VTKM_ASSERT(!currBIDs.empty());
|
||||
|
||||
std::vector<vtkm::Id> newIDs;
|
||||
if (p.Status.CheckSpatialBounds() && !p.Status.CheckTookAnySteps())
|
||||
newIDs.assign(std::next(currBIDs.begin(), 1), currBIDs.end());
|
||||
else
|
||||
newIDs = this->BoundsMap.FindBlocks(p.Pos, currBIDs);
|
||||
|
||||
//reset the particle status.
|
||||
p.Status = vtkm::ParticleStatus();
|
||||
|
||||
if (newIDs.empty()) //No blocks, we're done.
|
||||
{
|
||||
p.Status.SetTerminate();
|
||||
termIdx.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we have more than blockId, we want to minimize communication
|
||||
//and put any blocks owned by this rank first.
|
||||
if (newIDs.size() > 1)
|
||||
{
|
||||
for (auto idit = newIDs.begin(); idit != newIDs.end(); idit++)
|
||||
{
|
||||
vtkm::Id bid = *idit;
|
||||
if (this->BoundsMap.FindRank(bid) == this->Rank)
|
||||
{
|
||||
newIDs.erase(idit);
|
||||
newIDs.insert(newIDs.begin(), bid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dstRank = this->BoundsMap.FindRank(newIDs[0]);
|
||||
if (dstRank == this->Rank)
|
||||
{
|
||||
A.push_back(p);
|
||||
idsMapA[p.ID] = newIDs;
|
||||
}
|
||||
else
|
||||
{
|
||||
I.push_back(p);
|
||||
idsMapI[p.ID] = newIDs;
|
||||
}
|
||||
}
|
||||
portal.Set(i, p);
|
||||
}
|
||||
}
|
||||
|
||||
vtkm::Id numTerm = static_cast<vtkm::Id>(T.size());
|
||||
//Make sure we didn't miss anything. Every particle goes into a single bucket.
|
||||
VTKM_ASSERT(static_cast<std::size_t>(n) == (A.size() + I.size() + termIdx.size()));
|
||||
}
|
||||
|
||||
|
||||
vtkm::Id UpdateResult(ResultType& res, vtkm::Id blockId)
|
||||
{
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Id>> idsMapI, idsMapA;
|
||||
std::vector<vtkm::Particle> A, I;
|
||||
std::vector<vtkm::Id> termIdx;
|
||||
this->ClassifyParticles(res.Particles, idsMapA, idsMapI, A, I, termIdx);
|
||||
|
||||
//Update active, inactive and terminated
|
||||
this->UpdateActive(A, idsMapA);
|
||||
this->UpdateInactive(I, idsMapI);
|
||||
this->UpdateTerminated(T, blockId);
|
||||
|
||||
this->StoreResult(res, blockId);
|
||||
vtkm::Id numTerm = static_cast<vtkm::Id>(termIdx.size());
|
||||
if (numTerm > 0)
|
||||
this->UpdateTerminated(res.Particles, termIdx);
|
||||
|
||||
internal::ResultHelper<ResultType>::Store(this->Results, res, blockId, termIdx);
|
||||
|
||||
return numTerm;
|
||||
}
|
||||
|
||||
@ -348,8 +536,6 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void StoreResult(const ResultType& res, vtkm::Id blockId);
|
||||
|
||||
//Member data
|
||||
std::vector<vtkm::Particle> Active;
|
||||
std::vector<DataSetIntegratorType> Blocks;
|
||||
@ -364,16 +550,10 @@ protected:
|
||||
vtkm::FloatDefault StepSize;
|
||||
vtkm::Id TotalNumParticles;
|
||||
vtkm::Id TotalNumTerminatedParticles;
|
||||
std::unordered_map<vtkm::Id, std::vector<vtkm::Particle>> Terminated;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::filter::particleadvection
|
||||
|
||||
|
||||
#ifndef vtk_m_filter_particleadvection_AdvectorBaseAlgorithm_hxx
|
||||
#include <vtkm/filter/particleadvection/AdvectorBaseAlgorithm.hxx>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -22,15 +22,14 @@ namespace filter
|
||||
namespace particleadvection
|
||||
{
|
||||
|
||||
template <typename ResultType>
|
||||
class VTKM_ALWAYS_EXPORT AdvectorBaseThreadedAlgorithm : public AdvectorBaseAlgorithm<ResultType>
|
||||
template <typename DataSetIntegratorType, typename ResultType>
|
||||
class VTKM_ALWAYS_EXPORT AdvectorBaseThreadedAlgorithm
|
||||
: public AdvectorBaseAlgorithm<DataSetIntegratorType, ResultType>
|
||||
{
|
||||
public:
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
AdvectorBaseThreadedAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
: AdvectorBaseAlgorithm<ResultType>(bm, blocks)
|
||||
: AdvectorBaseAlgorithm<DataSetIntegratorType, ResultType>(bm, blocks)
|
||||
, Done(false)
|
||||
, WorkerActivate(false)
|
||||
{
|
||||
@ -57,7 +56,8 @@ protected:
|
||||
bool GetActiveParticles(std::vector<vtkm::Particle>& particles, vtkm::Id& blockId) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->Mutex);
|
||||
bool val = this->AdvectorBaseAlgorithm<ResultType>::GetActiveParticles(particles, blockId);
|
||||
bool val = this->AdvectorBaseAlgorithm<DataSetIntegratorType, ResultType>::GetActiveParticles(
|
||||
particles, blockId);
|
||||
this->WorkerActivate = val;
|
||||
return val;
|
||||
}
|
||||
@ -68,7 +68,8 @@ protected:
|
||||
if (!particles.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->Mutex);
|
||||
this->AdvectorBaseAlgorithm<ResultType>::UpdateActive(particles, idsMap);
|
||||
this->AdvectorBaseAlgorithm<DataSetIntegratorType, ResultType>::UpdateActive(particles,
|
||||
idsMap);
|
||||
|
||||
//Let workers know there is new work
|
||||
this->WorkerActivateCondition.notify_all();
|
||||
@ -106,7 +107,6 @@ protected:
|
||||
if (this->GetActiveParticles(v, blockId))
|
||||
{
|
||||
const auto& block = this->GetDataSet(blockId);
|
||||
|
||||
ResultType r;
|
||||
block.Advect(v, this->StepSize, this->NumberOfSteps, r);
|
||||
this->UpdateWorkerResult(blockId, r);
|
||||
@ -127,11 +127,10 @@ protected:
|
||||
this->GetWorkerResults(workerResults);
|
||||
|
||||
vtkm::Id numTerm = 0;
|
||||
for (const auto& it : workerResults)
|
||||
for (auto& it : workerResults)
|
||||
{
|
||||
vtkm::Id blockId = it.first;
|
||||
const auto& results = it.second;
|
||||
for (const auto& r : results)
|
||||
for (auto& r : it.second)
|
||||
numTerm += this->UpdateResult(r, blockId);
|
||||
}
|
||||
|
||||
@ -151,7 +150,8 @@ protected:
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->Mutex);
|
||||
|
||||
return (this->AdvectorBaseAlgorithm<ResultType>::GetBlockAndWait(numLocalTerm) &&
|
||||
return (this->AdvectorBaseAlgorithm<DataSetIntegratorType, ResultType>::GetBlockAndWait(
|
||||
numLocalTerm) &&
|
||||
!this->WorkerActivate && this->WorkerResults.empty());
|
||||
}
|
||||
|
||||
|
@ -10,10 +10,10 @@
|
||||
|
||||
set(headers
|
||||
AdvectorBaseAlgorithm.h
|
||||
AdvectorBaseAlgorithm.hxx
|
||||
AdvectorBaseThreadedAlgorithm.h
|
||||
BoundsMap.h
|
||||
DataSetIntegrator.h
|
||||
DataSetIntegrator.hxx
|
||||
Messenger.h
|
||||
ParticleAdvectionAlgorithm.h
|
||||
ParticleMessenger.h
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/worklet/ParticleAdvection.h>
|
||||
#include <vtkm/worklet/particleadvection/RK4Integrator.h>
|
||||
#include <vtkm/worklet/particleadvection/TemporalGridEvaluators.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -26,31 +27,19 @@ namespace filter
|
||||
namespace particleadvection
|
||||
{
|
||||
|
||||
class VTKM_ALWAYS_EXPORT DataSetIntegrator
|
||||
template <typename GridEvalType>
|
||||
class VTKM_ALWAYS_EXPORT DataSetIntegratorBase
|
||||
{
|
||||
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
|
||||
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
|
||||
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
|
||||
public:
|
||||
DataSetIntegrator(const vtkm::cont::DataSet& ds, vtkm::Id id, std::string fieldNm)
|
||||
: ActiveField(ds.GetField(fieldNm))
|
||||
, CopySeedArray(false)
|
||||
DataSetIntegratorBase(bool copySeeds = false, vtkm::Id id = -1)
|
||||
: CopySeedArray(copySeeds)
|
||||
, Eval(nullptr)
|
||||
, ID(id)
|
||||
{
|
||||
auto fieldData = this->ActiveField.GetData();
|
||||
FieldHandle fieldArray;
|
||||
|
||||
if (fieldData.IsType<FieldHandle>())
|
||||
fieldArray = fieldData.AsArrayHandle<FieldHandle>();
|
||||
else
|
||||
vtkm::cont::ArrayCopy(fieldData, fieldArray);
|
||||
|
||||
this->Eval = std::shared_ptr<GridEvalType>(new GridEvalType(ds, fieldArray));
|
||||
}
|
||||
|
||||
~DataSetIntegratorBase() = default;
|
||||
|
||||
vtkm::Id GetID() const { return this->ID; }
|
||||
void SetCopySeedFlag(bool val) { this->CopySeedArray = val; }
|
||||
|
||||
@ -66,46 +55,88 @@ public:
|
||||
this->DoAdvect(seedArray, rk4, maxSteps, result);
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
using FieldHandleType = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
|
||||
|
||||
template <typename ResultType>
|
||||
inline void DoAdvect(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const RK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
ResultType& result) const;
|
||||
|
||||
vtkm::cont::Field ActiveField;
|
||||
FieldHandleType GetFieldHandle(const vtkm::cont::DataSet& ds, const std::string& fieldNm)
|
||||
{
|
||||
if (!ds.HasField(fieldNm))
|
||||
throw vtkm::cont::ErrorFilterExecution("Field " + fieldNm + " not found on dataset.");
|
||||
|
||||
FieldHandleType fieldArray;
|
||||
auto fieldData = ds.GetField(fieldNm).GetData();
|
||||
if (fieldData.IsType<FieldHandleType>())
|
||||
fieldArray = fieldData.AsArrayHandle<FieldHandleType>();
|
||||
else
|
||||
vtkm::cont::ArrayCopy(
|
||||
fieldData.ResetTypes<vtkm::TypeListFieldVec3, VTKM_DEFAULT_STORAGE_LIST>(), fieldArray);
|
||||
|
||||
return fieldArray;
|
||||
}
|
||||
|
||||
bool CopySeedArray;
|
||||
std::shared_ptr<GridEvalType> Eval;
|
||||
vtkm::Id ID;
|
||||
};
|
||||
|
||||
//-----
|
||||
// Specialization for ParticleAdvection worklet
|
||||
template <>
|
||||
inline void DataSetIntegrator::DoAdvect(
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const RK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>& result) const
|
||||
class VTKM_ALWAYS_EXPORT DataSetIntegrator
|
||||
: public DataSetIntegratorBase<vtkm::worklet::particleadvection::GridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<vtkm::cont::ArrayHandle<vtkm::Vec3f>>>>
|
||||
{
|
||||
vtkm::worklet::ParticleAdvection Worklet;
|
||||
result = Worklet.Run(rk4, seeds, maxSteps);
|
||||
}
|
||||
public:
|
||||
DataSetIntegrator(const vtkm::cont::DataSet& ds, vtkm::Id id, const std::string& fieldNm)
|
||||
: DataSetIntegratorBase<vtkm::worklet::particleadvection::GridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<FieldHandleType>>>(false, id)
|
||||
{
|
||||
auto fieldArray = this->GetFieldHandle(ds, fieldNm);
|
||||
|
||||
//-----
|
||||
// Specialization for Streamline worklet
|
||||
template <>
|
||||
inline void DataSetIntegrator::DoAdvect(
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const RK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
vtkm::worklet::StreamlineResult<vtkm::Particle>& result) const
|
||||
using EvalType = vtkm::worklet::particleadvection::GridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<FieldHandleType>>;
|
||||
|
||||
this->Eval = std::shared_ptr<EvalType>(new EvalType(ds, fieldArray));
|
||||
}
|
||||
};
|
||||
|
||||
class VTKM_ALWAYS_EXPORT TemporalDataSetIntegrator
|
||||
: public DataSetIntegratorBase<vtkm::worklet::particleadvection::TemporalGridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<vtkm::cont::ArrayHandle<vtkm::Vec3f>>>>
|
||||
{
|
||||
vtkm::worklet::Streamline Worklet;
|
||||
result = Worklet.Run(rk4, seeds, maxSteps);
|
||||
}
|
||||
using FieldHandleType = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
|
||||
|
||||
public:
|
||||
TemporalDataSetIntegrator(const vtkm::cont::DataSet& ds1,
|
||||
vtkm::FloatDefault t1,
|
||||
const vtkm::cont::DataSet& ds2,
|
||||
vtkm::FloatDefault t2,
|
||||
vtkm::Id id,
|
||||
const std::string& fieldNm)
|
||||
: DataSetIntegratorBase<vtkm::worklet::particleadvection::TemporalGridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<FieldHandleType>>>(false, id)
|
||||
{
|
||||
auto fieldArray1 = this->GetFieldHandle(ds1, fieldNm);
|
||||
auto fieldArray2 = this->GetFieldHandle(ds2, fieldNm);
|
||||
|
||||
using EvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<FieldHandleType>>;
|
||||
|
||||
this->Eval =
|
||||
std::shared_ptr<EvalType>(new EvalType(ds1, t1, fieldArray1, ds2, t2, fieldArray2));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::filter::particleadvection
|
||||
|
||||
#ifndef vtk_m_filter_particleadvection_DataSetIntegrator_hxx
|
||||
#include <vtkm/filter/particleadvection/DataSetIntegrator.hxx>
|
||||
#endif
|
||||
|
||||
#endif //vtk_m_filter_DataSetIntegrator_h
|
||||
|
74
vtkm/filter/particleadvection/DataSetIntegrator.hxx
Normal file
74
vtkm/filter/particleadvection/DataSetIntegrator.hxx
Normal file
@ -0,0 +1,74 @@
|
||||
//============================================================================
|
||||
// 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_DataSetIntegrator_hxx
|
||||
#define vtk_m_filter_DataSetIntegrator_hxx
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace filter
|
||||
{
|
||||
namespace particleadvection
|
||||
{
|
||||
|
||||
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<vtkm::cont::ArrayHandle<vtkm::Vec3f>>>;
|
||||
using TemporalGridEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<
|
||||
vtkm::worklet::particleadvection::VelocityField<vtkm::cont::ArrayHandle<vtkm::Vec3f>>>;
|
||||
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
|
||||
using TemporalRK4Type = vtkm::worklet::particleadvection::RK4Integrator<TemporalGridEvalType>;
|
||||
|
||||
//-----
|
||||
// Specialization for ParticleAdvection worklet
|
||||
template <>
|
||||
template <>
|
||||
inline void DataSetIntegratorBase<GridEvalType>::DoAdvect(
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const RK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>& result) const
|
||||
{
|
||||
vtkm::worklet::ParticleAdvection Worklet;
|
||||
result = Worklet.Run(rk4, seeds, maxSteps);
|
||||
}
|
||||
|
||||
//-----
|
||||
// Specialization for Streamline worklet
|
||||
template <>
|
||||
template <>
|
||||
inline void DataSetIntegratorBase<GridEvalType>::DoAdvect(
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const RK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
vtkm::worklet::StreamlineResult<vtkm::Particle>& result) const
|
||||
{
|
||||
vtkm::worklet::Streamline Worklet;
|
||||
result = Worklet.Run(rk4, seeds, maxSteps);
|
||||
}
|
||||
|
||||
//-----
|
||||
// Specialization for Pathline worklet
|
||||
template <>
|
||||
template <>
|
||||
inline void DataSetIntegratorBase<TemporalGridEvalType>::DoAdvect(
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds,
|
||||
const TemporalRK4Type& rk4,
|
||||
vtkm::Id maxSteps,
|
||||
vtkm::worklet::StreamlineResult<vtkm::Particle>& result) const
|
||||
{
|
||||
vtkm::worklet::Streamline Worklet;
|
||||
result = Worklet.Run(rk4, seeds, maxSteps);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::filter::particleadvection
|
||||
|
||||
#endif
|
@ -22,28 +22,29 @@ namespace filter
|
||||
namespace particleadvection
|
||||
{
|
||||
|
||||
class VTKM_ALWAYS_EXPORT ParticleAdvectionAlgorithm
|
||||
: public AdvectorBaseAlgorithm<vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
using DSIType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
class VTKM_ALWAYS_EXPORT ParticleAdvectionAlgorithm
|
||||
: public AdvectorBaseAlgorithm<DSIType, vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>
|
||||
{
|
||||
public:
|
||||
ParticleAdvectionAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
: AdvectorBaseAlgorithm<vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>(bm, blocks)
|
||||
const std::vector<DSIType>& blocks)
|
||||
: AdvectorBaseAlgorithm<DSIType, vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>(bm,
|
||||
blocks)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class VTKM_ALWAYS_EXPORT ParticleAdvectionThreadedAlgorithm
|
||||
: public AdvectorBaseThreadedAlgorithm<vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>
|
||||
: public AdvectorBaseThreadedAlgorithm<DSIType,
|
||||
vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
public:
|
||||
ParticleAdvectionThreadedAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
: AdvectorBaseThreadedAlgorithm<vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>(bm,
|
||||
const std::vector<DSIType>& blocks)
|
||||
: AdvectorBaseThreadedAlgorithm<DSIType,
|
||||
vtkm::worklet::ParticleAdvectionResult<vtkm::Particle>>(bm,
|
||||
blocks)
|
||||
{
|
||||
}
|
||||
|
@ -22,28 +22,55 @@ namespace filter
|
||||
namespace particleadvection
|
||||
{
|
||||
|
||||
class VTKM_ALWAYS_EXPORT StreamlineAlgorithm
|
||||
: public AdvectorBaseAlgorithm<vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
using DSIType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
using TDSIType = vtkm::filter::particleadvection::TemporalDataSetIntegrator;
|
||||
|
||||
class VTKM_ALWAYS_EXPORT StreamlineAlgorithm
|
||||
: public AdvectorBaseAlgorithm<DSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
{
|
||||
public:
|
||||
StreamlineAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
: AdvectorBaseAlgorithm<vtkm::worklet::StreamlineResult<vtkm::Particle>>(bm, blocks)
|
||||
const std::vector<DSIType>& blocks)
|
||||
: AdvectorBaseAlgorithm<DSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>(bm, blocks)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class VTKM_ALWAYS_EXPORT StreamlineThreadedAlgorithm
|
||||
: public AdvectorBaseThreadedAlgorithm<vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
: public AdvectorBaseThreadedAlgorithm<DSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
{
|
||||
using DataSetIntegratorType = vtkm::filter::particleadvection::DataSetIntegrator;
|
||||
|
||||
public:
|
||||
StreamlineThreadedAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<DataSetIntegratorType>& blocks)
|
||||
: AdvectorBaseThreadedAlgorithm<vtkm::worklet::StreamlineResult<vtkm::Particle>>(bm, blocks)
|
||||
const std::vector<DSIType>& blocks)
|
||||
: AdvectorBaseThreadedAlgorithm<DSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>(
|
||||
bm,
|
||||
blocks)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//pathline
|
||||
class VTKM_ALWAYS_EXPORT PathlineAlgorithm
|
||||
: public AdvectorBaseAlgorithm<TDSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
{
|
||||
public:
|
||||
PathlineAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<TDSIType>& blocks)
|
||||
: AdvectorBaseAlgorithm<TDSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>(bm, blocks)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class VTKM_ALWAYS_EXPORT PathlineThreadedAlgorithm
|
||||
: public AdvectorBaseThreadedAlgorithm<TDSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>
|
||||
{
|
||||
public:
|
||||
PathlineThreadedAlgorithm(const vtkm::filter::particleadvection::BoundsMap& bm,
|
||||
const std::vector<TDSIType>& blocks)
|
||||
: AdvectorBaseThreadedAlgorithm<TDSIType, vtkm::worklet::StreamlineResult<vtkm::Particle>>(
|
||||
bm,
|
||||
blocks)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -554,6 +554,7 @@ void TestStreamlineFilters()
|
||||
TestStreamline();
|
||||
TestPathlineSimple();
|
||||
TestPathline();
|
||||
|
||||
for (auto useSL : flags)
|
||||
TestAMRStreamline(useSL);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/filter/ParticleAdvection.h>
|
||||
#include <vtkm/filter/Pathline.h>
|
||||
#include <vtkm/filter/Streamline.h>
|
||||
#include <vtkm/worklet/testing/GenerateTestDataSets.h>
|
||||
|
||||
@ -18,6 +19,13 @@
|
||||
namespace
|
||||
{
|
||||
|
||||
enum FilterType
|
||||
{
|
||||
PARTICLE_ADVECTION,
|
||||
STREAMLINE,
|
||||
PATHLINE
|
||||
};
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> CreateConstantVectorField(vtkm::Id num, const vtkm::Vec3f& vec)
|
||||
{
|
||||
vtkm::cont::ArrayHandleConstant<vtkm::Vec3f> vecConst;
|
||||
@ -36,7 +44,22 @@ void AddVectorFields(vtkm::cont::PartitionedDataSet& pds,
|
||||
ds.AddPointField(fieldName, CreateConstantVectorField(ds.GetNumberOfPoints(), vec));
|
||||
}
|
||||
|
||||
void TestAMRStreamline(bool useSL, bool useThreaded)
|
||||
template <typename FilterType>
|
||||
void SetFilter(FilterType& filter,
|
||||
vtkm::FloatDefault stepSize,
|
||||
vtkm::Id numSteps,
|
||||
const std::string& fieldName,
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray,
|
||||
bool useThreaded)
|
||||
{
|
||||
filter.SetStepSize(stepSize);
|
||||
filter.SetNumberOfSteps(numSteps);
|
||||
filter.SetSeeds(seedArray);
|
||||
filter.SetActiveField(fieldName);
|
||||
filter.SetUseThreadedAlgorithm(useThreaded);
|
||||
}
|
||||
|
||||
void TestAMRStreamline(FilterType fType, bool useThreaded)
|
||||
{
|
||||
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
||||
if (comm.size() < 2)
|
||||
@ -102,16 +125,30 @@ void TestAMRStreamline(bool useSL, bool useThreaded)
|
||||
seedArray = vtkm::cont::make_ArrayHandle({ p0, p1 });
|
||||
vtkm::Id numSeeds = seedArray.GetNumberOfValues();
|
||||
|
||||
if (useSL)
|
||||
{
|
||||
vtkm::filter::Streamline filter;
|
||||
filter.SetUseThreadedAlgorithm(useThreaded);
|
||||
filter.SetStepSize(0.1f);
|
||||
filter.SetNumberOfSteps(100000);
|
||||
filter.SetSeeds(seedArray);
|
||||
vtkm::FloatDefault stepSize = 0.1f;
|
||||
vtkm::Id numSteps = 100000;
|
||||
|
||||
filter.SetActiveField(fieldName);
|
||||
auto out = filter.Execute(pds);
|
||||
if (fType == STREAMLINE || fType == PATHLINE)
|
||||
{
|
||||
vtkm::cont::PartitionedDataSet out;
|
||||
|
||||
if (fType == STREAMLINE)
|
||||
{
|
||||
vtkm::filter::Streamline streamline;
|
||||
SetFilter(streamline, stepSize, numSteps, fieldName, seedArray, useThreaded);
|
||||
out = streamline.Execute(pds);
|
||||
}
|
||||
else if (fType == PATHLINE)
|
||||
{
|
||||
vtkm::filter::Pathline pathline;
|
||||
SetFilter(pathline, stepSize, numSteps, fieldName, seedArray, useThreaded);
|
||||
//Create timestep 2
|
||||
auto pds2 = vtkm::cont::PartitionedDataSet(pds);
|
||||
pathline.SetPreviousTime(0);
|
||||
pathline.SetNextTime(10);
|
||||
pathline.SetNextDataSet(pds2);
|
||||
out = pathline.Execute(pds);
|
||||
}
|
||||
|
||||
if (comm.rank() <= 1)
|
||||
VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 1, "Wrong number of partitions in output");
|
||||
@ -185,7 +222,7 @@ void TestAMRStreamline(bool useSL, bool useThreaded)
|
||||
"Seed final location in wrong location");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (fType == PARTICLE_ADVECTION)
|
||||
{
|
||||
vtkm::filter::ParticleAdvection filter;
|
||||
filter.SetUseThreadedAlgorithm(useThreaded);
|
||||
@ -221,7 +258,44 @@ void TestAMRStreamline(bool useSL, bool useThreaded)
|
||||
}
|
||||
}
|
||||
|
||||
void TestPartitionedDataSet(vtkm::Id nPerRank, bool useGhost, bool useSL, bool useThreaded)
|
||||
void ValidateOutput(const vtkm::cont::DataSet& out,
|
||||
vtkm::Id numSeeds,
|
||||
vtkm::Range xMaxRange,
|
||||
FilterType fType)
|
||||
{
|
||||
//Validate the result is correct.
|
||||
VTKM_TEST_ASSERT(out.GetNumberOfCoordinateSystems() == 1,
|
||||
"Wrong number of coordinate systems in the output dataset");
|
||||
|
||||
vtkm::cont::DynamicCellSet dcells = out.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == 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<vtkm::cont::CellSetExplicit<>>(), "Wrong cell type.");
|
||||
explicitCells = dcells.Cast<vtkm::cont::CellSetExplicit<>>();
|
||||
for (vtkm::Id j = 0; j < numSeeds; j++)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> indices;
|
||||
explicitCells.GetIndices(j, indices);
|
||||
vtkm::Id nPts = indices.GetNumberOfValues();
|
||||
auto iPortal = indices.ReadPortal();
|
||||
vtkm::Vec3f lastPt = ptPortal.Get(iPortal.Get(nPts - 1));
|
||||
VTKM_TEST_ASSERT(xMaxRange.Contains(lastPt[0]), "Wrong end point for seed");
|
||||
}
|
||||
}
|
||||
else if (fType == PARTICLE_ADVECTION)
|
||||
{
|
||||
VTKM_TEST_ASSERT(out.GetNumberOfPoints() == numSeeds, "Wrong number of coordinates");
|
||||
for (vtkm::Id i = 0; i < numSeeds; 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)
|
||||
{
|
||||
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
||||
|
||||
@ -243,6 +317,9 @@ void TestPartitionedDataSet(vtkm::Id nPerRank, bool useGhost, bool useSL, bool u
|
||||
z1 = z1 + 1;
|
||||
}
|
||||
|
||||
vtkm::FloatDefault time0 = 0;
|
||||
vtkm::FloatDefault time1 = (numDims - 1) * (nPerRank * comm.size());
|
||||
|
||||
std::vector<vtkm::Bounds> bounds;
|
||||
for (vtkm::Id i = 0; i < nPerRank; i++)
|
||||
{
|
||||
@ -251,14 +328,28 @@ void TestPartitionedDataSet(vtkm::Id nPerRank, bool useGhost, bool useSL, bool u
|
||||
x1 += dx;
|
||||
}
|
||||
|
||||
std::vector<vtkm::cont::PartitionedDataSet> allPDs;
|
||||
std::vector<vtkm::Range> xMaxRanges;
|
||||
for (const auto& b : bounds)
|
||||
{
|
||||
auto xMax = b.X.Max;
|
||||
if (useGhost)
|
||||
xMax = xMax - 1;
|
||||
xMaxRanges.push_back(vtkm::Range(xMax, xMax + static_cast<vtkm::FloatDefault>(.5)));
|
||||
}
|
||||
|
||||
|
||||
std::vector<vtkm::cont::PartitionedDataSet> allPDS, allPDS2;
|
||||
const vtkm::Id3 dims(numDims, numDims, numDims);
|
||||
allPDs = vtkm::worklet::testing::CreateAllDataSets(bounds, dims, useGhost);
|
||||
allPDS = vtkm::worklet::testing::CreateAllDataSets(bounds, dims, useGhost);
|
||||
allPDS2 = vtkm::worklet::testing::CreateAllDataSets(bounds, dims, useGhost);
|
||||
|
||||
vtkm::Vec3f vecX(1, 0, 0);
|
||||
std::string fieldName = "vec";
|
||||
for (auto& pds : allPDs)
|
||||
vtkm::FloatDefault stepSize = 0.1f;
|
||||
vtkm::Id numSteps = 100000;
|
||||
for (std::size_t n = 0; n < allPDS.size(); n++)
|
||||
{
|
||||
auto pds = allPDS[n];
|
||||
AddVectorFields(pds, fieldName, vecX);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
|
||||
@ -266,107 +357,65 @@ void TestPartitionedDataSet(vtkm::Id nPerRank, bool useGhost, bool useSL, bool u
|
||||
vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1) });
|
||||
vtkm::Id numSeeds = seedArray.GetNumberOfValues();
|
||||
|
||||
if (useSL)
|
||||
if (fType == STREAMLINE)
|
||||
{
|
||||
vtkm::filter::Streamline streamline;
|
||||
|
||||
streamline.SetUseThreadedAlgorithm(useThreaded);
|
||||
streamline.SetStepSize(0.1f);
|
||||
streamline.SetNumberOfSteps(100000);
|
||||
streamline.SetSeeds(seedArray);
|
||||
|
||||
streamline.SetActiveField(fieldName);
|
||||
SetFilter(streamline, stepSize, numSteps, fieldName, seedArray, useThreaded);
|
||||
auto out = streamline.Execute(pds);
|
||||
|
||||
for (vtkm::Id i = 0; i < nPerRank; i++)
|
||||
{
|
||||
auto inputDS = pds.GetPartition(i);
|
||||
auto outputDS = out.GetPartition(i);
|
||||
VTKM_TEST_ASSERT(outputDS.GetNumberOfCoordinateSystems() == 1,
|
||||
"Wrong number of coordinate systems in the output dataset");
|
||||
|
||||
vtkm::cont::DynamicCellSet dcells = outputDS.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == numSeeds, "Wrong number of cells");
|
||||
|
||||
auto coords = outputDS.GetCoordinateSystem().GetDataAsMultiplexer();
|
||||
auto ptPortal = coords.ReadPortal();
|
||||
|
||||
vtkm::cont::CellSetExplicit<> explicitCells;
|
||||
|
||||
VTKM_TEST_ASSERT(dcells.IsType<vtkm::cont::CellSetExplicit<>>(), "Wrong cell type.");
|
||||
explicitCells = dcells.Cast<vtkm::cont::CellSetExplicit<>>();
|
||||
|
||||
vtkm::FloatDefault xMax = bounds[static_cast<std::size_t>(i)].X.Max;
|
||||
if (useGhost)
|
||||
xMax = xMax - 1;
|
||||
vtkm::Range xMaxRange(xMax, xMax + static_cast<vtkm::FloatDefault>(.5));
|
||||
|
||||
for (vtkm::Id j = 0; j < numSeeds; j++)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> indices;
|
||||
explicitCells.GetIndices(j, indices);
|
||||
vtkm::Id nPts = indices.GetNumberOfValues();
|
||||
auto iPortal = indices.ReadPortal();
|
||||
vtkm::Vec3f lastPt = ptPortal.Get(iPortal.Get(nPts - 1));
|
||||
VTKM_TEST_ASSERT(xMaxRange.Contains(lastPt[0]), "Wrong end point for seed");
|
||||
}
|
||||
}
|
||||
ValidateOutput(out.GetPartition(i), numSeeds, xMaxRanges[i], fType);
|
||||
}
|
||||
else
|
||||
else if (fType == PARTICLE_ADVECTION)
|
||||
{
|
||||
vtkm::filter::ParticleAdvection particleAdvection;
|
||||
|
||||
particleAdvection.SetUseThreadedAlgorithm(useThreaded);
|
||||
particleAdvection.SetStepSize(0.1f);
|
||||
particleAdvection.SetNumberOfSteps(100000);
|
||||
particleAdvection.SetSeeds(seedArray);
|
||||
|
||||
particleAdvection.SetActiveField(fieldName);
|
||||
SetFilter(particleAdvection, stepSize, numSteps, fieldName, seedArray, useThreaded);
|
||||
auto out = particleAdvection.Execute(pds);
|
||||
|
||||
//Particles end up in last rank.
|
||||
if (comm.rank() == comm.size() - 1)
|
||||
{
|
||||
VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 1, "Wrong number of partitions in output");
|
||||
auto ds = out.GetPartition(0);
|
||||
//Validate the result is correct.
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"Wrong number of coordinate systems in the output dataset");
|
||||
|
||||
vtkm::FloatDefault xMax = bounds[bounds.size() - 1].X.Max;
|
||||
if (useGhost)
|
||||
xMax = xMax - 1;
|
||||
vtkm::Range xMaxRange(xMax, xMax + static_cast<vtkm::FloatDefault>(.5));
|
||||
|
||||
auto coords = ds.GetCoordinateSystem().GetDataAsMultiplexer();
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == numSeeds, "Wrong number of coordinates");
|
||||
auto ptPortal = coords.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < numSeeds; i++)
|
||||
VTKM_TEST_ASSERT(xMaxRange.Contains(ptPortal.Get(i)[0]), "Wrong end point for seed");
|
||||
|
||||
vtkm::cont::DynamicCellSet dcells = ds.GetCellSet();
|
||||
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == numSeeds, "Wrong number of cells");
|
||||
ValidateOutput(out.GetPartition(0), numSeeds, xMaxRanges[xMaxRanges.size() - 1], fType);
|
||||
}
|
||||
else
|
||||
VTKM_TEST_ASSERT(out.GetNumberOfPartitions() == 0, "Wrong number of partitions in output");
|
||||
}
|
||||
else if (fType == PATHLINE)
|
||||
{
|
||||
auto pds2 = allPDS2[n];
|
||||
AddVectorFields(pds2, fieldName, vecX);
|
||||
|
||||
vtkm::filter::Pathline pathline;
|
||||
SetFilter(pathline, stepSize, numSteps, fieldName, seedArray, useThreaded);
|
||||
|
||||
pathline.SetPreviousTime(time0);
|
||||
pathline.SetNextTime(time1);
|
||||
pathline.SetNextDataSet(pds2);
|
||||
|
||||
auto out = pathline.Execute(pds);
|
||||
for (vtkm::Id i = 0; i < nPerRank; i++)
|
||||
ValidateOutput(out.GetPartition(i), numSeeds, xMaxRanges[i], fType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestStreamlineFiltersMPI()
|
||||
{
|
||||
std::vector<bool> flags = { true, false };
|
||||
std::vector<FilterType> filterTypes = { PARTICLE_ADVECTION, STREAMLINE, PATHLINE };
|
||||
|
||||
for (int n = 1; n < 3; n++)
|
||||
{
|
||||
for (auto useGhost : flags)
|
||||
for (auto useSL : flags)
|
||||
for (auto fType : filterTypes)
|
||||
for (auto useThreaded : flags)
|
||||
TestPartitionedDataSet(n, useGhost, useSL, useThreaded);
|
||||
TestPartitionedDataSet(n, useGhost, fType, useThreaded);
|
||||
}
|
||||
|
||||
for (auto useSL : flags)
|
||||
for (auto fType : filterTypes)
|
||||
for (auto useThreaded : flags)
|
||||
TestAMRStreamline(useSL, useThreaded);
|
||||
TestAMRStreamline(fType, useThreaded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,21 @@ private:
|
||||
public:
|
||||
VTKM_CONT TemporalGridEvaluator() = default;
|
||||
|
||||
VTKM_CONT TemporalGridEvaluator(const vtkm::cont::DataSet& ds1,
|
||||
const vtkm::FloatDefault t1,
|
||||
const FieldType& field1,
|
||||
const vtkm::cont::DataSet& ds2,
|
||||
const vtkm::FloatDefault t2,
|
||||
const FieldType& field2)
|
||||
: EvaluatorOne(GridEvaluator(ds1, field1))
|
||||
, EvaluatorTwo(GridEvaluator(ds2, field2))
|
||||
, TimeOne(t1)
|
||||
, TimeTwo(t2)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VTKM_CONT TemporalGridEvaluator(GridEvaluator& evaluatorOne,
|
||||
const vtkm::FloatDefault timeOne,
|
||||
GridEvaluator& evaluatorTwo,
|
||||
|
Loading…
Reference in New Issue
Block a user