Generalize fields for particle advection

This commit is contained in:
dpugmire 2020-07-20 21:15:46 -04:00
parent 502c310cf8
commit 31c97bed89
29 changed files with 858 additions and 289 deletions

@ -11,6 +11,8 @@
#define vtk_m_Particle_h
#include <vtkm/Bitset.h>
#include <vtkm/VecVariable.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
@ -68,6 +70,12 @@ public:
VTKM_EXEC_CONT
Particle() {}
VTKM_EXEC_CONT virtual ~Particle() noexcept
{
// This must not be defaulted, since defaulted virtual destructors are
// troublesome with CUDA __host__ __device__ markup.
}
VTKM_EXEC_CONT
Particle(const vtkm::Vec3f& p,
const vtkm::Id& id,
@ -92,7 +100,20 @@ public:
{
}
vtkm::Particle& operator=(const vtkm::Particle& p) = default;
vtkm::Particle& operator=(const vtkm::Particle&) = default;
// The basic particle is only meant to be advected in a velocity
// field. In that case it is safe to assume that the velocity value
// will always be stored in the first location of vectors
VTKM_EXEC_CONT
virtual vtkm::Vec3f Next(const vtkm::VecVariable<vtkm::Vec3f, 2>&, const vtkm::FloatDefault&) = 0;
// The basic particle is only meant to be advected in a velocity
// field. In that case it is safe to assume that the velocity value
// will always be stored in the first location of vectors
VTKM_EXEC_CONT
virtual vtkm::Vec3f Velocity(const vtkm::VecVariable<vtkm::Vec3f, 2>&,
const vtkm::FloatDefault&) = 0;
vtkm::Vec3f Pos;
vtkm::Id ID = -1;
@ -100,6 +121,141 @@ public:
vtkm::ParticleStatus Status;
vtkm::FloatDefault Time = 0;
};
}
class Massless : public vtkm::Particle
{
public:
VTKM_EXEC_CONT
Massless() {}
VTKM_EXEC_CONT ~Massless() noexcept override
{
// This must not be defaulted, since defaulted virtual destructors are
// troublesome with CUDA __host__ __device__ markup.
}
VTKM_EXEC_CONT
Massless(const vtkm::Vec3f& p,
const vtkm::Id& id,
const vtkm::Id& numSteps = 0,
const vtkm::ParticleStatus& status = vtkm::ParticleStatus(),
const vtkm::FloatDefault& time = 0)
: Particle(p, id, numSteps, status, time)
{
}
/*VTKM_EXEC_CONT
Massless(const vtkm::Massless& p)
: Particle(p)
{
}*/
VTKM_EXEC_CONT
vtkm::Vec3f Next(const vtkm::VecVariable<vtkm::Vec3f, 2>& vectors,
const vtkm::FloatDefault& length) override
{
VTKM_ASSERT(vectors.GetNumberOfComponents() > 0);
return this->Pos + length * vectors[0];
}
VTKM_EXEC_CONT
vtkm::Vec3f Velocity(const vtkm::VecVariable<vtkm::Vec3f, 2>& vectors,
const vtkm::FloatDefault& vtkmNotUsed(length)) override
{
// Velocity is evaluated from the Velocity field
// and is not influenced by the particle
VTKM_ASSERT(vectors.GetNumberOfComponents() > 0);
return vectors[0];
}
};
class Electron : public vtkm::Particle
{
public:
VTKM_EXEC_CONT
Electron() {}
VTKM_EXEC_CONT
Electron(const vtkm::Vec3f& position,
const vtkm::Id& id,
const vtkm::FloatDefault& mass,
const vtkm::FloatDefault& charge,
const vtkm::FloatDefault& weighting,
const vtkm::Vec3f& momentum,
const vtkm::Id& numSteps = 0,
const vtkm::ParticleStatus& status = vtkm::ParticleStatus(),
const vtkm::FloatDefault& time = 0)
: Particle(position, id, numSteps, status, time)
, Mass(mass)
, Charge(charge)
, Weighting(weighting)
, Momentum(momentum)
{
}
VTKM_EXEC_CONT
vtkm::FloatDefault Beta(vtkm::Vec3f momentum) const
{
return static_cast<vtkm::FloatDefault>(vtkm::Magnitude(momentum / this->Mass) /
vtkm::Pow(SPEED_OF_LIGHT, 2));
}
VTKM_EXEC_CONT
vtkm::Vec3f Next(const vtkm::VecVariable<vtkm::Vec3f, 2>& vectors,
const vtkm::FloatDefault& length) override
{
// TODO: implement Lorentz force calculation
return this->Pos + length * this->Velocity(vectors, length);
}
VTKM_EXEC_CONT
vtkm::Vec3f Velocity(const vtkm::VecVariable<vtkm::Vec3f, 2>& vectors,
const vtkm::FloatDefault& length) override
{
VTKM_ASSERT(vectors.GetNumberOfComponents() == 2);
// Suppress unused warning
(void)this->Weighting;
vtkm::Vec3f velocity;
// Particle has a charge and a mass
// Velocity updated using Lorentz force
// Return velocity of the particle
vtkm::Vec3f eField = vectors[0];
vtkm::Vec3f bField = vectors[1];
const vtkm::FloatDefault QoM = this->Charge / this->Mass;
const vtkm::FloatDefault half = 0.5;
const vtkm::Vec3f mom_ = this->Momentum + (half * this->Charge * eField * length);
//TODO : Calculate Gamma
vtkm::Vec3f gamma_reci = vtkm::Sqrt(1 - this->Beta(mom_));
// gamma(mom_, mass) -> needs velocity calculation
const vtkm::Vec3f t = half * QoM * bField * gamma_reci * length;
const vtkm::Vec3f s = 2.0f * t * (1 / 1 + vtkm::Magnitude(t));
const vtkm::Vec3f mom_pr = mom_ + vtkm::Cross(mom_, t);
const vtkm::Vec3f mom_pl = mom_ + vtkm::Cross(mom_pr, s);
const vtkm::Vec3f mom_new = mom_pl + 0.5 * this->Charge * eField * length;
//TODO : this is a const method, figure a better way to update momentum
this->Momentum = mom_new;
velocity = mom_new / this->Mass;
return velocity;
}
private:
vtkm::FloatDefault Mass;
vtkm::FloatDefault Charge;
vtkm::FloatDefault Weighting;
vtkm::Vec3f Momentum;
constexpr static vtkm::FloatDefault SPEED_OF_LIGHT =
static_cast<vtkm::FloatDefault>(2.99792458e8);
};
} //namespace vtkm
#endif // vtk_m_Particle_h

@ -65,11 +65,16 @@ public:
VTKM_EXEC_CONT
inline const ComponentType& operator[](vtkm::IdComponent index) const
{
VTKM_ASSERT(index >= 0 && index < this->NumComponents);
return this->Data[index];
}
VTKM_EXEC_CONT
inline ComponentType& operator[](vtkm::IdComponent index) { return this->Data[index]; }
inline ComponentType& operator[](vtkm::IdComponent index)
{
VTKM_ASSERT(index >= 0 && index < this->NumComponents);
return this->Data[index];
}
VTKM_EXEC_CONT
void Append(ComponentType value)

@ -130,6 +130,7 @@ set(template_sources
ColorTable.hxx
FieldRangeCompute.hxx
FieldRangeGlobalCompute.hxx
ParticleArrayCopy.hxx
StorageVirtual.hxx
VirtualObjectHandle.hxx
)
@ -150,7 +151,6 @@ set(sources
internal/VirtualObjectTransfer.cxx
Initialize.cxx
Logging.cxx
ParticleArrayCopy.cxx
RuntimeDeviceTracker.cxx
Token.cxx
TryExecute.cxx
@ -184,7 +184,6 @@ set(sources
Field.cxx
FieldRangeCompute.cxx
FieldRangeGlobalCompute.cxx
ParticleArrayCopy.cxx
PartitionedDataSet.cxx
PointLocator.cxx
PointLocatorUniformGrid.cxx

@ -24,9 +24,10 @@ namespace cont
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
/// position field into an \c ArrayHandle of \c Vec3f objects.
///
VTKM_CONT_EXPORT
VTKM_CONT void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
template <typename ParticleType>
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>& inP,
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos);
/// \brief Copy all fields in vtkm::Particle to standard types.
@ -35,9 +36,10 @@ VTKM_CONT void ParticleArrayCopy(
/// position, ID, number of steps, status and time into a separate
/// \c ArrayHandle.
///
VTKM_CONT_EXPORT
VTKM_CONT void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<vtkm::Particle, vtkm::cont::StorageTagBasic>& inP,
template <typename ParticleType>
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>& inP,
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos,
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outID,
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outSteps,
@ -46,4 +48,8 @@ VTKM_CONT void ParticleArrayCopy(
}
} // namespace vtkm::cont
#ifndef vtk_m_cont_ParticleArrayCopy_hxx
#include <vtkm/cont/ParticleArrayCopy.hxx>
#endif //vtk_m_cont_ParticleArrayCopy_hxx
#endif //vtk_m_cont_ParticleArrayCopy_h

@ -0,0 +1,97 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_ParticleArrayCopy_hxx
#define vtk_m_cont_ParticleArrayCopy_hxx
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/ParticleArrayCopy.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace cont
{
namespace detail
{
struct CopyParticlePositionWorklet : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn inParticle, FieldOut outPos);
VTKM_EXEC void operator()(const vtkm::Particle& inParticle, vtkm::Vec3f& outPos) const
{
outPos = inParticle.Pos;
}
};
struct CopyParticleAllWorklet : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn inParticle,
FieldOut outPos,
FieldOut outID,
FieldOut outSteps,
FieldOut outStatus,
FieldOut outTime);
VTKM_EXEC void operator()(const vtkm::Particle& inParticle,
vtkm::Vec3f& outPos,
vtkm::Id& outID,
vtkm::Id& outSteps,
vtkm::ParticleStatus& outStatus,
vtkm::FloatDefault& outTime) const
{
outPos = inParticle.Pos;
outID = inParticle.ID;
outSteps = inParticle.NumSteps;
outStatus = inParticle.Status;
outTime = inParticle.Time;
}
};
} // namespace detail
template <typename ParticleType>
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>& inP,
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos)
{
vtkm::cont::Invoker invoke;
detail::CopyParticlePositionWorklet worklet;
invoke(worklet, inP, outPos);
}
/// \brief Copy all fields in vtkm::Particle to standard types.
///
/// Given an \c ArrayHandle of vtkm::Particle, this function copies the
/// position, ID, number of steps, status and time into a separate
/// \c ArrayHandle.
///
template <typename ParticleType>
VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
const vtkm::cont::ArrayHandle<ParticleType, vtkm::cont::StorageTagBasic>& inP,
vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagBasic>& outPos,
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outID,
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>& outSteps,
vtkm::cont::ArrayHandle<vtkm::ParticleStatus, vtkm::cont::StorageTagBasic>& outStatus,
vtkm::cont::ArrayHandle<vtkm::FloatDefault, vtkm::cont::StorageTagBasic>& outTime)
{
vtkm::cont::Invoker invoke;
detail::CopyParticleAllWorklet worklet;
invoke(worklet, inP, outPos, outID, outSteps, outStatus, outTime);
}
}
} // namespace vtkm::cont
#endif //vtk_m_cont_ParticleArrayCopy_hxx

@ -19,14 +19,14 @@ void TestParticleArrayCopy()
vtkm::FloatDefault x0(-1), x1(1);
std::uniform_real_distribution<vtkm::FloatDefault> dist(x0, x1);
std::vector<vtkm::Particle> particles;
std::vector<vtkm::Massless> particles;
vtkm::Id N = 17;
for (vtkm::Id i = 0; i < N; i++)
{
auto x = dist(generator);
auto y = dist(generator);
auto z = dist(generator);
particles.push_back(vtkm::Particle(vtkm::Vec3f(x, y, z), i));
particles.push_back(vtkm::Massless(vtkm::Vec3f(x, y, z), i));
}
for (int i = 0; i < 2; i++)
@ -37,7 +37,7 @@ void TestParticleArrayCopy()
if (i == 0)
{
vtkm::cont::ArrayHandle<vtkm::Vec3f> pos;
vtkm::cont::ParticleArrayCopy(particleAH, pos);
vtkm::cont::ParticleArrayCopy<vtkm::Massless>(particleAH, pos);
auto pPortal = particleAH.ReadPortal();
for (vtkm::Id j = 0; j < N; j++)
@ -54,7 +54,7 @@ void TestParticleArrayCopy()
vtkm::cont::ArrayHandle<vtkm::ParticleStatus> status;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> ptime;
vtkm::cont::ParticleArrayCopy(particleAH, pos, ids, steps, status, ptime);
vtkm::cont::ParticleArrayCopy<vtkm::Massless>(particleAH, pos, ids, steps, status, ptime);
auto pPortal = particleAH.ReadPortal();
for (vtkm::Id j = 0; j < N; j++)

@ -23,6 +23,7 @@
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/worklet/ParticleAdvection.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -32,8 +33,8 @@
#include <string.h>
static vtkm::Id cycle = 0;
static vtkm::cont::ArrayHandle<vtkm::Particle> BasisParticles;
static vtkm::cont::ArrayHandle<vtkm::Particle> BasisParticlesOriginal;
static vtkm::cont::ArrayHandle<vtkm::Massless> BasisParticles;
static vtkm::cont::ArrayHandle<vtkm::Massless> BasisParticlesOriginal;
static vtkm::cont::ArrayHandle<vtkm::Id> BasisParticlesValidity;
namespace
@ -51,7 +52,7 @@ public:
}
template <typename ValidityType>
VTKM_EXEC void operator()(const vtkm::Particle& end_point, ValidityType& res) const
VTKM_EXEC void operator()(const vtkm::Massless& end_point, ValidityType& res) const
{
vtkm::Id steps = end_point.NumSteps;
if (steps > 0 && res == 1)
@ -83,8 +84,8 @@ public:
using InputDomain = _1;
template <typename DisplacementType>
VTKM_EXEC void operator()(const vtkm::Particle& end_point,
const vtkm::Particle& start_point,
VTKM_EXEC void operator()(const vtkm::Massless& end_point,
const vtkm::Massless& start_point,
DisplacementType& res) const
{
res[0] = end_point.Pos[0] - start_point.Pos[0];
@ -193,7 +194,7 @@ inline void Lagrangian::InitializeSeedPositions(const vtkm::cont::DataSet& input
{
vtkm::FloatDefault xi = static_cast<vtkm::FloatDefault>(x * x_spacing);
portal1.Set(id,
vtkm::Particle(Vec3f(static_cast<vtkm::FloatDefault>(bounds.X.Min) + xi,
vtkm::Massless(Vec3f(static_cast<vtkm::FloatDefault>(bounds.X.Min) + xi,
static_cast<vtkm::FloatDefault>(bounds.Y.Min) + yi,
static_cast<vtkm::FloatDefault>(bounds.Z.Min) + zi),
id));
@ -264,7 +265,7 @@ inline VTKM_CONT vtkm::cont::DataSet Lagrangian::DoExecute(
throw vtkm::cont::ErrorFilterExecution(
"Write frequency can not be 0. Use SetWriteFrequency().");
}
vtkm::cont::ArrayHandle<vtkm::Particle> basisParticleArray;
vtkm::cont::ArrayHandle<vtkm::Massless> basisParticleArray;
vtkm::cont::ArrayCopy(BasisParticles, basisParticleArray);
cycle += 1;
@ -274,12 +275,14 @@ inline VTKM_CONT vtkm::cont::DataSet Lagrangian::DoExecute(
vtkm::Bounds bounds = input.GetCoordinateSystem().GetBounds();
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
vtkm::worklet::ParticleAdvection particleadvection;
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
GridEvalType gridEval(coords, cells, field);
FieldType velocities(field);
GridEvalType gridEval(coords, cells, velocities);
RK4Type rk4(gridEval, static_cast<vtkm::Float32>(this->stepSize));
res = particleadvection.Run(rk4, basisParticleArray, 1); // Taking a single step

@ -14,6 +14,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -34,12 +35,28 @@ public:
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
VTKM_EXEC void operator()(const vtkm::Particle& particle, vtkm::Vec3f& pt) const
VTKM_EXEC void operator()(const vtkm::Massless& particle, vtkm::Vec3f& pt) const
{
pt = particle.Pos;
}
};
class MakeParticles : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn seed, FieldOut particle);
using ExecutionSignature = void(WorkIndex, _1, _2);
using InputDomain = _1;
VTKM_EXEC void operator()(const vtkm::Id index,
const vtkm::Vec3f& seed,
vtkm::Massless& particle) const
{
particle.ID = index;
particle.Pos = seed;
}
};
} //detail
//-----------------------------------------------------------------------------
@ -66,7 +83,8 @@ inline VTKM_CONT vtkm::cont::DataSet LagrangianStructures::DoExecute(
using Structured3DType = vtkm::cont::CellSetStructured<3>;
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using Integrator = vtkm::worklet::particleadvection::RK4Integrator<GridEvaluator>;
vtkm::FloatDefault stepSize = this->GetStepSize();
@ -115,15 +133,16 @@ inline VTKM_CONT vtkm::cont::DataSet LagrangianStructures::DoExecute(
}
else
{
GridEvaluator evaluator(input.GetCoordinateSystem(), input.GetCellSet(), field);
vtkm::cont::Invoker invoke;
FieldType velocities(field);
GridEvaluator evaluator(input.GetCoordinateSystem(), input.GetCellSet(), velocities);
Integrator integrator(evaluator, stepSize);
vtkm::worklet::ParticleAdvection particles;
vtkm::worklet::ParticleAdvectionResult advectionResult;
vtkm::cont::ArrayHandle<vtkm::Vec3f> advectionPoints;
vtkm::cont::ArrayCopy(lcsInputPoints, advectionPoints);
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> advectionResult;
vtkm::cont::ArrayHandle<vtkm::Massless> advectionPoints;
invoke(detail::MakeParticles{}, lcsInputPoints, advectionPoints);
advectionResult = particles.Run(integrator, advectionPoints, numberOfSteps);
vtkm::cont::Invoker invoke;
invoke(detail::ExtractParticlePosition{}, advectionResult.Particles, lcsOutputPoints);
}
// FTLE output field

@ -39,7 +39,7 @@ public:
void SetNumberOfSteps(vtkm::Id n) { this->NumberOfSteps = n; }
VTKM_CONT
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds);
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds);
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
@ -56,7 +56,7 @@ public:
private:
vtkm::Id NumberOfSteps;
vtkm::FloatDefault StepSize;
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
vtkm::cont::ArrayHandle<vtkm::Massless> Seeds;
vtkm::worklet::ParticleAdvection Worklet;
};
}

@ -34,7 +34,7 @@ inline VTKM_CONT ParticleAdvection::ParticleAdvection()
}
//-----------------------------------------------------------------------------
inline VTKM_CONT void ParticleAdvection::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds)
inline VTKM_CONT void ParticleAdvection::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds)
{
this->Seeds = seeds;
}
@ -63,15 +63,16 @@ inline VTKM_CONT vtkm::cont::DataSet ParticleAdvection::DoExecute(
}
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
GridEvalType eval(coords, cells, field);
RK4Type rk4(eval, this->StepSize);
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
res = this->Worklet.Run(rk4, seedArray, this->NumberOfSteps);
@ -79,7 +80,7 @@ inline VTKM_CONT vtkm::cont::DataSet ParticleAdvection::DoExecute(
//Copy particles to coordinate array
vtkm::cont::ArrayHandle<vtkm::Vec3f> outPos;
vtkm::cont::ParticleArrayCopy(res.Particles, outPos);
vtkm::cont::ParticleArrayCopy<vtkm::Massless>(res.Particles, outPos);
vtkm::cont::CoordinateSystem outCoords("coordinates", outPos);
outData.AddCoordinateSystem(outCoords);

@ -47,7 +47,7 @@ public:
void SetNumberOfSteps(vtkm::Id n) { this->NumberOfSteps = n; }
VTKM_CONT
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds);
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds);
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
@ -68,7 +68,7 @@ private:
vtkm::FloatDefault NextTime;
vtkm::cont::DataSet NextDataSet;
vtkm::Id NumberOfSteps;
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
vtkm::cont::ArrayHandle<vtkm::Massless> Seeds;
};
}
} // namespace vtkm::filter

@ -14,6 +14,7 @@
#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/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -32,7 +33,7 @@ inline VTKM_CONT Pathline::Pathline()
}
//-----------------------------------------------------------------------------
inline VTKM_CONT void Pathline::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds)
inline VTKM_CONT void Pathline::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds)
{
this->Seeds = seeds;
}
@ -67,17 +68,20 @@ inline VTKM_CONT vtkm::cont::DataSet Pathline::DoExecute(
}
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
FieldType velocities(field);
FieldType velocities2(field2);
GridEvalType eval(
coords, cells, field, this->PreviousTime, coords2, cells2, field2, this->NextTime);
coords, cells, velocities, this->PreviousTime, coords2, cells2, velocities2, this->NextTime);
RK4Type rk4(eval, this->StepSize);
vtkm::worklet::Streamline streamline;
vtkm::worklet::StreamlineResult res;
vtkm::worklet::StreamlineResult<vtkm::Massless> res;
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
res = Worklet.Run(rk4, seedArray, this->NumberOfSteps);

@ -40,7 +40,7 @@ public:
void SetNumberOfSteps(vtkm::Id n) { this->NumberOfSteps = n; }
VTKM_CONT
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds) { this->Seeds = seeds; }
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds) { this->Seeds = seeds; }
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
@ -56,7 +56,7 @@ public:
private:
vtkm::Id NumberOfSteps;
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
vtkm::cont::ArrayHandle<vtkm::Massless> Seeds;
vtkm::FloatDefault StepSize;
vtkm::worklet::StreamSurface Worklet;
};

@ -17,6 +17,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/worklet/ParticleAdvection.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -53,16 +54,18 @@ inline VTKM_CONT vtkm::cont::DataSet StreamSurface::DoExecute(
throw vtkm::cont::ErrorFilterExecution("Point field expected.");
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
//compute streamlines
GridEvalType eval(coords, cells, field);
FieldType velocities(field);
GridEvalType eval(coords, cells, velocities);
RK4Type rk4(eval, this->StepSize);
vtkm::worklet::Streamline streamline;
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
auto res = streamline.Run(rk4, seedArray, this->NumberOfSteps);

@ -39,7 +39,7 @@ public:
void SetNumberOfSteps(vtkm::Id n) { this->NumberOfSteps = n; }
VTKM_CONT
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds);
void SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds);
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
@ -56,7 +56,7 @@ public:
private:
vtkm::Id NumberOfSteps;
vtkm::FloatDefault StepSize;
vtkm::cont::ArrayHandle<vtkm::Particle> Seeds;
vtkm::cont::ArrayHandle<vtkm::Massless> Seeds;
vtkm::worklet::Streamline Worklet;
};
}

@ -15,6 +15,7 @@
#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/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -32,7 +33,7 @@ inline VTKM_CONT Streamline::Streamline()
}
//-----------------------------------------------------------------------------
inline VTKM_CONT void Streamline::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Particle>& seeds)
inline VTKM_CONT void Streamline::SetSeeds(vtkm::cont::ArrayHandle<vtkm::Massless>& seeds)
{
this->Seeds = seeds;
}
@ -61,15 +62,17 @@ inline VTKM_CONT vtkm::cont::DataSet Streamline::DoExecute(
}
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
GridEvalType eval(coords, cells, field);
FieldType velocities(field);
GridEvalType eval(coords, cells, velocities);
RK4Type rk4(eval, this->StepSize);
vtkm::worklet::StreamlineResult res;
vtkm::worklet::StreamlineResult<vtkm::Massless> res;
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
vtkm::cont::ArrayCopy(this->Seeds, seedArray);
res = this->Worklet.Run(rk4, seedArray, this->NumberOfSteps);

@ -37,11 +37,11 @@ void TestBasic()
const vtkm::Vec3f vecX(1, 0, 0);
vtkm::cont::DataSet ds = CreateDataSet(dims, vecX);
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
std::vector<vtkm::Particle> seeds(3);
seeds[0] = vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Particle(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
std::vector<vtkm::Massless> seeds(3);
seeds[0] = vtkm::Massless(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Massless(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Massless(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
seedArray = vtkm::cont::make_ArrayHandle(seeds);
@ -88,9 +88,9 @@ void TestFile(const std::string& fname,
}
vtkm::Id numPoints = static_cast<vtkm::Id>(pts.size());
std::vector<vtkm::Particle> seeds;
std::vector<vtkm::Massless> seeds;
for (vtkm::Id i = 0; i < numPoints; i++)
seeds.push_back(vtkm::Particle(pts[static_cast<std::size_t>(i)], i));
seeds.push_back(vtkm::Massless(pts[static_cast<std::size_t>(i)], i));
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
vtkm::filter::ParticleAdvection particleAdvection;

@ -38,12 +38,12 @@ void TestStreamSurface()
const vtkm::Vec3f vecX(1, 0, 0);
vtkm::cont::DataSet ds = CreateDataSet(dims, vecX);
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
std::vector<vtkm::Particle> seeds(4);
seeds[0] = vtkm::Particle(vtkm::Vec3f(.1f, 1.0f, .2f), 0);
seeds[1] = vtkm::Particle(vtkm::Vec3f(.1f, 2.0f, .1f), 1);
seeds[2] = vtkm::Particle(vtkm::Vec3f(.1f, 3.0f, .3f), 2);
seeds[3] = vtkm::Particle(vtkm::Vec3f(.1f, 3.5f, .2f), 3);
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
std::vector<vtkm::Massless> seeds(4);
seeds[0] = vtkm::Massless(vtkm::Vec3f(.1f, 1.0f, .2f), 0);
seeds[1] = vtkm::Massless(vtkm::Vec3f(.1f, 2.0f, .1f), 1);
seeds[2] = vtkm::Massless(vtkm::Vec3f(.1f, 3.0f, .3f), 2);
seeds[3] = vtkm::Massless(vtkm::Vec3f(.1f, 3.5f, .2f), 3);
seedArray = vtkm::cont::make_ArrayHandle(seeds);

@ -38,11 +38,11 @@ void TestStreamline()
const vtkm::Vec3f vecX(1, 0, 0);
vtkm::cont::DataSet ds = CreateDataSet(dims, vecX);
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
std::vector<vtkm::Particle> seeds(3);
seeds[0] = vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Particle(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
std::vector<vtkm::Massless> seeds(3);
seeds[0] = vtkm::Massless(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Massless(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Massless(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
seedArray = vtkm::cont::make_ArrayHandle(seeds);
@ -75,11 +75,11 @@ void TestPathline()
vtkm::cont::DataSet ds1 = CreateDataSet(dims, vecX);
vtkm::cont::DataSet ds2 = CreateDataSet(dims, vecY);
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
std::vector<vtkm::Particle> seeds(3);
seeds[0] = vtkm::Particle(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Particle(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Particle(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
vtkm::cont::ArrayHandle<vtkm::Massless> seedArray;
std::vector<vtkm::Massless> seeds(3);
seeds[0] = vtkm::Massless(vtkm::Vec3f(.2f, 1.0f, .2f), 0);
seeds[1] = vtkm::Massless(vtkm::Vec3f(.2f, 2.0f, .2f), 1);
seeds[2] = vtkm::Massless(vtkm::Vec3f(.2f, 3.0f, .2f), 2);
seedArray = vtkm::cont::make_ArrayHandle(seeds);
@ -126,9 +126,9 @@ void TestStreamlineFile(const std::string& fname,
}
vtkm::Id numPoints = static_cast<vtkm::Id>(pts.size());
std::vector<vtkm::Particle> seeds;
std::vector<vtkm::Massless> seeds;
for (vtkm::Id i = 0; i < numPoints; i++)
seeds.push_back(vtkm::Particle(pts[static_cast<std::size_t>(i)], i));
seeds.push_back(vtkm::Massless(pts[static_cast<std::size_t>(i)], i));
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
vtkm::filter::Streamline streamline;

@ -48,6 +48,7 @@ public:
} //detail
template <typename ParticleType>
struct ParticleAdvectionResult
{
ParticleAdvectionResult()
@ -55,12 +56,12 @@ struct ParticleAdvectionResult
{
}
ParticleAdvectionResult(const vtkm::cont::ArrayHandle<vtkm::Particle>& p)
ParticleAdvectionResult(const vtkm::cont::ArrayHandle<ParticleType>& p)
: Particles(p)
{
}
vtkm::cont::ArrayHandle<vtkm::Particle> Particles;
vtkm::cont::ArrayHandle<ParticleType> Particles;
};
class ParticleAdvection
@ -68,25 +69,29 @@ class ParticleAdvection
public:
ParticleAdvection() {}
template <typename IntegratorType, typename ParticleStorage>
ParticleAdvectionResult Run(const IntegratorType& it,
vtkm::cont::ArrayHandle<vtkm::Particle, ParticleStorage>& particles,
vtkm::Id MaxSteps)
template <typename IntegratorType, typename ParticleType, typename ParticleStorage>
ParticleAdvectionResult<ParticleType> Run(
const IntegratorType& it,
vtkm::cont::ArrayHandle<ParticleType, ParticleStorage>& particles,
vtkm::Id MaxSteps)
{
vtkm::worklet::particleadvection::ParticleAdvectionWorklet<IntegratorType> worklet;
vtkm::worklet::particleadvection::ParticleAdvectionWorklet<IntegratorType, ParticleType>
worklet;
worklet.Run(it, particles, MaxSteps);
return ParticleAdvectionResult(particles);
return ParticleAdvectionResult<ParticleType>(particles);
}
template <typename IntegratorType, typename PointStorage>
ParticleAdvectionResult Run(const IntegratorType& it,
const vtkm::cont::ArrayHandle<vtkm::Vec3f, PointStorage>& points,
vtkm::Id MaxSteps)
template <typename IntegratorType, typename ParticleType, typename PointStorage>
ParticleAdvectionResult<ParticleType> Run(
const IntegratorType& it,
const vtkm::cont::ArrayHandle<vtkm::Vec3f, PointStorage>& points,
vtkm::Id MaxSteps)
{
vtkm::worklet::particleadvection::ParticleAdvectionWorklet<IntegratorType> worklet;
vtkm::worklet::particleadvection::ParticleAdvectionWorklet<IntegratorType, ParticleType>
worklet;
vtkm::cont::ArrayHandle<vtkm::Particle> particles;
vtkm::cont::ArrayHandle<ParticleType> particles;
vtkm::cont::ArrayHandle<vtkm::Id> step, ids;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> time;
vtkm::cont::Invoker invoke;
@ -103,10 +108,11 @@ public:
invoke(detail::CopyToParticle{}, points, ids, time, step, particles);
worklet.Run(it, particles, MaxSteps);
return ParticleAdvectionResult(particles);
return ParticleAdvectionResult<ParticleType>(particles);
}
};
template <typename ParticleType>
struct StreamlineResult
{
StreamlineResult()
@ -116,7 +122,7 @@ struct StreamlineResult
{
}
StreamlineResult(const vtkm::cont::ArrayHandle<vtkm::Particle>& part,
StreamlineResult(const vtkm::cont::ArrayHandle<ParticleType>& part,
const vtkm::cont::ArrayHandle<vtkm::Vec3f>& pos,
const vtkm::cont::CellSetExplicit<>& lines)
: Particles(part)
@ -125,7 +131,7 @@ struct StreamlineResult
{
}
vtkm::cont::ArrayHandle<vtkm::Particle> Particles;
vtkm::cont::ArrayHandle<ParticleType> Particles;
vtkm::cont::ArrayHandle<vtkm::Vec3f> Positions;
vtkm::cont::CellSetExplicit<> PolyLines;
};
@ -135,19 +141,20 @@ class Streamline
public:
Streamline() {}
template <typename IntegratorType, typename ParticleStorage>
StreamlineResult Run(const IntegratorType& it,
vtkm::cont::ArrayHandle<vtkm::Particle, ParticleStorage>& particles,
vtkm::Id MaxSteps)
template <typename IntegratorType, typename ParticleType, typename ParticleStorage>
StreamlineResult<ParticleType> Run(
const IntegratorType& it,
vtkm::cont::ArrayHandle<ParticleType, ParticleStorage>& particles,
vtkm::Id MaxSteps)
{
vtkm::worklet::particleadvection::StreamlineWorklet<IntegratorType> worklet;
vtkm::worklet::particleadvection::StreamlineWorklet<IntegratorType, ParticleType> worklet;
vtkm::cont::ArrayHandle<vtkm::Vec3f> positions;
vtkm::cont::CellSetExplicit<> polyLines;
worklet.Run(it, particles, MaxSteps, positions, polyLines);
return StreamlineResult(particles, positions, polyLines);
return StreamlineResult<ParticleType>(particles, positions, polyLines);
}
};
}

@ -10,6 +10,7 @@
set(headers
CellInterpolationHelper.h
Field.h
GridEvaluators.h
GridEvaluatorStatus.h
Integrators.h

@ -0,0 +1,220 @@
//============================================================================
// 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 vtkm_woklet_particleadvection_field_h
#define vtkm_woklet_particleadvection_field_h
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/exec/CellInterpolate.h>
namespace vtkm
{
namespace worklet
{
namespace particleadvection
{
class ExecutionField : public vtkm::VirtualObjectBase
{
public:
VTKM_EXEC_CONT
virtual ~ExecutionField() noexcept override {}
VTKM_EXEC
virtual void GetValue(const vtkm::VecVariable<vtkm::Id, 8>& indices,
const vtkm::Id vertices,
const vtkm::Vec3f& parametric,
const vtkm::UInt8 cellShape,
vtkm::VecVariable<vtkm::Vec3f, 2>& value) const = 0;
};
template <typename DeviceAdapter, typename FieldArrayType>
class ExecutionVelocityField : public vtkm::worklet::particleadvection::ExecutionField
{
public:
using FieldPortalType =
typename FieldArrayType::template ExecutionTypes<DeviceAdapter>::PortalConst;
VTKM_CONT
ExecutionVelocityField(FieldArrayType velocityValues, vtkm::cont::Token& token)
: VelocityValues(velocityValues.PrepareForInput(DeviceAdapter(), token))
{
}
VTKM_EXEC void GetValue(const vtkm::VecVariable<vtkm::Id, 8>& indices,
const vtkm::Id vertices,
const vtkm::Vec3f& parametric,
const vtkm::UInt8 cellShape,
vtkm::VecVariable<vtkm::Vec3f, 2>& value) const
{
vtkm::Vec3f velocityInterp;
vtkm::VecVariable<vtkm::Vec3f, 8> velocities;
for (vtkm::IdComponent i = 0; i < vertices; i++)
velocities.Append(VelocityValues.Get(indices[i]));
vtkm::exec::CellInterpolate(velocities, parametric, cellShape, velocityInterp);
value = vtkm::make_Vec(velocityInterp);
}
private:
FieldPortalType VelocityValues;
};
template <typename DeviceAdapter, typename FieldArrayType>
class ExecutionElectroMagneticField : public vtkm::worklet::particleadvection::ExecutionField
{
public:
using FieldPortalType =
typename FieldArrayType::template ExecutionTypes<DeviceAdapter>::PortalConst;
VTKM_CONT
ExecutionElectroMagneticField(FieldArrayType electricValues,
FieldArrayType magneticValues,
vtkm::cont::Token& token)
: ElectricValues(electricValues.PrepareForInput(DeviceAdapter(), token))
, MagneticValues(magneticValues.PrepareForInput(DeviceAdapter(), token))
{
}
VTKM_EXEC void GetValue(const vtkm::VecVariable<vtkm::Id, 8>& indices,
const vtkm::Id vertices,
const vtkm::Vec3f& parametric,
const vtkm::UInt8 cellShape,
vtkm::VecVariable<vtkm::Vec3f, 2>& value) const
{
vtkm::Vec3f electricInterp, magneticInterp;
vtkm::VecVariable<vtkm::Vec3f, 8> electric;
vtkm::VecVariable<vtkm::Vec3f, 8> magnetic;
for (vtkm::IdComponent i = 0; i < vertices; i++)
{
electric.Append(ElectricValues.Get(indices[i]));
magnetic.Append(MagneticValues.Get(indices[i]));
}
vtkm::exec::CellInterpolate(electric, parametric, cellShape, electricInterp);
vtkm::exec::CellInterpolate(magnetic, parametric, cellShape, magneticInterp);
value = vtkm::make_Vec(electricInterp, magneticInterp);
}
private:
FieldPortalType ElectricValues;
FieldPortalType MagneticValues;
};
class Field : public vtkm::cont::ExecutionObjectBase
{
public:
using HandleType = vtkm::cont::VirtualObjectHandle<ExecutionField>;
virtual ~Field() = default;
VTKM_CONT
virtual const ExecutionField* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId,
vtkm::cont::Token& token) const = 0;
};
template <typename FieldArrayType>
class VelocityField : public vtkm::worklet::particleadvection::Field
{
public:
VTKM_CONT
VelocityField(const FieldArrayType& fieldValues)
: FieldValues(fieldValues)
{
}
struct VelocityFieldFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
FieldArrayType fieldValues,
HandleType& execHandle,
vtkm::cont::Token& token) const
{
using ExecutionType = ExecutionVelocityField<DeviceAdapter, FieldArrayType>;
ExecutionType* execObject = new ExecutionType(fieldValues, token);
execHandle.Reset(execObject);
return true;
}
};
VTKM_CONT
const ExecutionField* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId,
vtkm::cont::Token& token) const override
{
const bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, VelocityFieldFunctor(), this->FieldValues, this->ExecHandle, token);
if (!success)
{
throwFailedRuntimeDeviceTransfer("SingleCellTypeInterpolationHelper", deviceId);
}
return this->ExecHandle.PrepareForExecution(deviceId, token);
}
private:
FieldArrayType FieldValues;
mutable HandleType ExecHandle;
};
template <typename FieldArrayType>
class ElectroMagneticField : public vtkm::worklet::particleadvection::Field
{
public:
VTKM_CONT
ElectroMagneticField(const FieldArrayType& electricField, const FieldArrayType& magneticField)
: ElectricField(electricField)
, MagneticField(magneticField)
{
}
struct ElectroMagneticFieldFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter,
FieldArrayType electricField,
FieldArrayType magneticField,
HandleType& execHandle,
vtkm::cont::Token& token) const
{
using ExecutionType = ExecutionElectroMagneticField<DeviceAdapter, FieldArrayType>;
ExecutionType* execObject = new ExecutionType(electricField, magneticField, token);
execHandle.Reset(execObject);
return true;
}
};
VTKM_CONT
const ExecutionField* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId,
vtkm::cont::Token& token) const override
{
const bool success = vtkm::cont::TryExecuteOnDevice(deviceId,
ElectroMagneticFieldFunctor(),
this->ElectricField,
this->MagneticField,
this->ExecHandle,
token);
if (!success)
{
throwFailedRuntimeDeviceTransfer("SingleCellTypeInterpolationHelper", deviceId);
}
return this->ExecHandle.PrepareForExecution(deviceId, token);
}
private:
FieldArrayType ElectricField;
FieldArrayType MagneticField;
mutable HandleType ExecHandle;
};
} // namespace particleadvection
} // namespace worklet
} // namespace
#endif //vtkm_woklet_particleadvection_field_h

@ -24,6 +24,7 @@
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/worklet/particleadvection/CellInterpolationHelper.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/GridEvaluatorStatus.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
@ -34,12 +35,9 @@ namespace worklet
namespace particleadvection
{
template <typename DeviceAdapter, typename FieldArrayType>
template <typename DeviceAdapter, typename FieldType>
class ExecutionGridEvaluator
{
using FieldPortalType =
typename FieldArrayType::template ExecutionTypes<DeviceAdapter>::PortalConst;
public:
VTKM_CONT
ExecutionGridEvaluator() = default;
@ -48,13 +46,13 @@ public:
ExecutionGridEvaluator(std::shared_ptr<vtkm::cont::CellLocator> locator,
std::shared_ptr<vtkm::cont::CellInterpolationHelper> interpolationHelper,
const vtkm::Bounds& bounds,
const FieldArrayType& field,
const FieldType& field,
vtkm::cont::Token& token)
: Bounds(bounds)
, Field(field.PrepareForInput(DeviceAdapter(), token))
{
Locator = locator->PrepareForExecution(DeviceAdapter(), token);
InterpolationHelper = interpolationHelper->PrepareForExecution(DeviceAdapter(), token);
Field = field.PrepareForExecution(DeviceAdapter(), token);
}
template <typename Point>
@ -84,13 +82,13 @@ public:
template <typename Point>
VTKM_EXEC GridEvaluatorStatus Evaluate(const Point& pos,
vtkm::FloatDefault vtkmNotUsed(time),
Point& out) const
vtkm::VecVariable<Point, 2>& out) const
{
return this->Evaluate(pos, out);
}
template <typename Point>
VTKM_EXEC GridEvaluatorStatus Evaluate(const Point& point, Point& out) const
VTKM_EXEC GridEvaluatorStatus Evaluate(const Point& point, vtkm::VecVariable<Point, 2>& out) const
{
vtkm::Id cellId;
Point parametric;
@ -110,10 +108,11 @@ public:
vtkm::VecVariable<vtkm::Vec3f, 8> fieldValues;
InterpolationHelper->GetCellInfo(cellId, cellShape, nVerts, ptIndices);
for (vtkm::IdComponent i = 0; i < nVerts; i++)
fieldValues.Append(Field.Get(ptIndices[i]));
this->Field->GetValue(ptIndices, nVerts, parametric, cellShape, out);
//for (vtkm::IdComponent i = 0; i < nVerts; i++)
// fieldValues.Append(Field->GetValue(ptIndices[i]));
vtkm::exec::CellInterpolate(fieldValues, parametric, cellShape, out);
//vtkm::exec::CellInterpolate(fieldValues, parametric, cellShape, out);
status.SetOk();
return status;
@ -122,11 +121,11 @@ public:
private:
const vtkm::exec::CellLocator* Locator;
const vtkm::exec::CellInterpolationHelper* InterpolationHelper;
const vtkm::worklet::particleadvection::ExecutionField* Field;
vtkm::Bounds Bounds;
FieldPortalType Field;
};
template <typename FieldArrayType>
template <typename FieldType>
class GridEvaluator : public vtkm::cont::ExecutionObjectBase
{
public:
@ -143,8 +142,8 @@ public:
VTKM_CONT
GridEvaluator(const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::DynamicCellSet& cellset,
const FieldArrayType& field)
: Vectors(field)
const FieldType& field)
: Field(field)
, Bounds(coordinates.GetBounds())
{
if (cellset.IsSameType(Structured2DType()) || cellset.IsSameType(Structured3DType()))
@ -205,18 +204,18 @@ public:
}
template <typename DeviceAdapter>
VTKM_CONT ExecutionGridEvaluator<DeviceAdapter, FieldArrayType> PrepareForExecution(
VTKM_CONT ExecutionGridEvaluator<DeviceAdapter, FieldType> PrepareForExecution(
DeviceAdapter,
vtkm::cont::Token& token) const
{
return ExecutionGridEvaluator<DeviceAdapter, FieldArrayType>(
this->Locator, this->InterpolationHelper, this->Bounds, this->Vectors, token);
return ExecutionGridEvaluator<DeviceAdapter, FieldType>(
this->Locator, this->InterpolationHelper, this->Bounds, this->Field, token);
}
private:
std::shared_ptr<vtkm::cont::CellLocator> Locator;
std::shared_ptr<vtkm::cont::CellInterpolationHelper> InterpolationHelper;
FieldArrayType Vectors;
FieldType Field;
vtkm::Bounds Bounds;
};

@ -59,12 +59,12 @@ public:
public:
VTKM_EXEC
virtual IntegratorStatus Step(const vtkm::Vec3f& inpos,
virtual IntegratorStatus Step(vtkm::Particle* inpos,
vtkm::FloatDefault& time,
vtkm::Vec3f& outpos) const = 0;
VTKM_EXEC
virtual IntegratorStatus SmallStep(vtkm::Vec3f& inpos,
virtual IntegratorStatus SmallStep(vtkm::Particle* inpos,
vtkm::FloatDefault& time,
vtkm::Vec3f& outpos) const = 0;
@ -111,20 +111,20 @@ protected:
public:
VTKM_EXEC
IntegratorStatus Step(const vtkm::Vec3f& inpos,
IntegratorStatus Step(vtkm::Particle* particle,
vtkm::FloatDefault& time,
vtkm::Vec3f& outpos) const override
{
// If particle is out of either spatial or temporal boundary to begin with,
// then return the corresponding status.
IntegratorStatus status;
if (!this->Evaluator.IsWithinSpatialBoundary(inpos))
if (!this->Evaluator.IsWithinSpatialBoundary(particle->Pos))
{
status.SetFail();
status.SetSpatialBounds();
return status;
}
if (!this->Evaluator.IsWithinTemporalBoundary(time))
if (!this->Evaluator.IsWithinTemporalBoundary(particle->Time))
{
status.SetFail();
status.SetTemporalBounds();
@ -132,31 +132,31 @@ protected:
}
vtkm::Vec3f velocity;
status = CheckStep(inpos, this->StepLength, time, velocity);
status = CheckStep(particle, this->StepLength, velocity);
if (status.CheckOk())
{
outpos = inpos + StepLength * velocity;
time += StepLength;
outpos = particle->Pos + this->StepLength * velocity;
time += this->StepLength;
}
else
outpos = inpos;
outpos = particle->Pos;
return status;
}
VTKM_EXEC
IntegratorStatus SmallStep(vtkm::Vec3f& inpos,
IntegratorStatus SmallStep(vtkm::Particle* particle,
vtkm::FloatDefault& time,
vtkm::Vec3f& outpos) const override
{
if (!this->Evaluator.IsWithinSpatialBoundary(inpos))
if (!this->Evaluator.IsWithinSpatialBoundary(particle->Pos))
{
outpos = inpos;
outpos = particle->Pos;
return IntegratorStatus(false, true, false);
}
if (!this->Evaluator.IsWithinTemporalBoundary(time))
if (!this->Evaluator.IsWithinTemporalBoundary(particle->Time))
{
outpos = inpos;
outpos = particle->Pos;
return IntegratorStatus(false, false, true);
}
@ -170,14 +170,14 @@ protected:
//The binary search will be between {0, this->StepLength}
vtkm::FloatDefault stepRange[2] = { 0, this->StepLength };
vtkm::Vec3f currPos(inpos), currVel;
auto evalStatus = this->Evaluator.Evaluate(currPos, time, currVel);
vtkm::Vec3f currPos(particle->Pos), currVelocity;
vtkm::VecVariable<vtkm::Vec3f, 2> currValue, tmp;
auto evalStatus = this->Evaluator.Evaluate(currPos, particle->Time, currValue);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
const vtkm::FloatDefault eps = vtkm::Epsilon<vtkm::FloatDefault>() * 10;
vtkm::FloatDefault div = 1;
vtkm::Vec3f tmp;
while ((stepRange[1] - stepRange[0]) > eps)
{
//Try a step midway between stepRange[0] and stepRange[1]
@ -185,13 +185,13 @@ protected:
vtkm::FloatDefault stepCurr = stepRange[0] + (this->StepLength / div);
//See if we can step by stepCurr.
IntegratorStatus status = this->CheckStep(inpos, stepCurr, time, currVel);
IntegratorStatus status = this->CheckStep(particle, stepCurr, currVelocity);
if (status.CheckOk()) //Integration step succedded.
{
//See if this point is in/out.
auto newPos = inpos + stepCurr * currVel;
evalStatus = this->Evaluator.Evaluate(newPos, time + stepCurr, tmp);
auto newPos = particle->Pos + stepCurr * currVelocity;
evalStatus = this->Evaluator.Evaluate(newPos, particle->Time + stepCurr, tmp);
if (evalStatus.CheckOk())
{
//Point still in. Update currPos and set range to {stepCurr, stepRange[1]}
@ -211,22 +211,23 @@ protected:
stepRange[1] = stepCurr;
}
}
evalStatus = this->Evaluator.Evaluate(currPos, time + stepRange[0], currVel);
evalStatus = this->Evaluator.Evaluate(currPos, particle->Time + stepRange[0], currValue);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
//Update the position and time.
outpos = currPos + stepRange[1] * currVel;
outpos = currPos + stepRange[1] * particle->Velocity(currValue, stepRange[1]);
time += stepRange[1];
return IntegratorStatus(true, true, !this->Evaluator.IsWithinTemporalBoundary(time));
return IntegratorStatus(
true, true, !this->Evaluator.IsWithinTemporalBoundary(particle->Time));
}
VTKM_EXEC
IntegratorStatus CheckStep(const vtkm::Vec3f& inpos,
IntegratorStatus CheckStep(vtkm::Particle* particle,
vtkm::FloatDefault stepLength,
vtkm::FloatDefault time,
vtkm::Vec3f& velocity) const
{
return static_cast<const DerivedType*>(this)->CheckStep(inpos, stepLength, time, velocity);
return static_cast<const DerivedType*>(this)->CheckStep(particle, stepLength, velocity);
}
protected:
@ -295,11 +296,12 @@ public:
}
VTKM_EXEC
IntegratorStatus CheckStep(const vtkm::Vec3f& inpos,
IntegratorStatus CheckStep(vtkm::Particle* particle,
vtkm::FloatDefault stepLength,
vtkm::FloatDefault time,
vtkm::Vec3f& velocity) const
{
auto time = particle->Time;
auto inpos = particle->Pos;
vtkm::FloatDefault boundary = this->Evaluator.GetTemporalBoundary(static_cast<vtkm::Id>(1));
if ((time + stepLength + vtkm::Epsilon<vtkm::FloatDefault>() - boundary) > 0.0)
stepLength = boundary - time;
@ -314,24 +316,33 @@ public:
vtkm::FloatDefault var2 = time + var1;
vtkm::FloatDefault var3 = time + stepLength;
vtkm::Vec3f k1 = vtkm::TypeTraits<vtkm::Vec3f>::ZeroInitialization();
vtkm::Vec3f k2 = k1, k3 = k1, k4 = k1;
vtkm::Vec3f v1 = vtkm::TypeTraits<vtkm::Vec3f>::ZeroInitialization();
vtkm::Vec3f v2 = v1, v3 = v1, v4 = v1;
vtkm::VecVariable<vtkm::Vec3f, 2> k1, k2, k3, k4;
GridEvaluatorStatus evalStatus;
evalStatus = this->Evaluator.Evaluate(inpos, time, k1);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
evalStatus = this->Evaluator.Evaluate(inpos + var1 * k1, var2, k2);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
evalStatus = this->Evaluator.Evaluate(inpos + var1 * k2, var2, k3);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
evalStatus = this->Evaluator.Evaluate(inpos + stepLength * k3, var3, k4);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
v1 = particle->Velocity(k1, stepLength);
velocity = (k1 + 2 * k2 + 2 * k3 + k4) / static_cast<vtkm::FloatDefault>(6);
evalStatus = this->Evaluator.Evaluate(inpos + var1 * v1, var2, k2);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
v2 = particle->Velocity(k2, stepLength);
evalStatus = this->Evaluator.Evaluate(inpos + var1 * v2, var2, k3);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
v3 = particle->Velocity(k3, stepLength);
evalStatus = this->Evaluator.Evaluate(inpos + stepLength * v3, var3, k4);
if (evalStatus.CheckFail())
return IntegratorStatus(evalStatus);
v4 = particle->Velocity(k4, stepLength);
velocity = (v1 + 2 * v2 + 2 * v3 + v4) / static_cast<vtkm::FloatDefault>(6);
return IntegratorStatus(true, false, evalStatus.CheckTemporalBounds());
}
};
@ -391,12 +402,15 @@ public:
}
VTKM_EXEC
IntegratorStatus CheckStep(const vtkm::Vec3f& inpos,
vtkm::FloatDefault vtkmNotUsed(stepLength),
vtkm::FloatDefault time,
IntegratorStatus CheckStep(vtkm::Particle* particle,
vtkm::FloatDefault stepLength,
vtkm::Vec3f& velocity) const
{
GridEvaluatorStatus status = this->Evaluator.Evaluate(inpos, time, velocity);
auto time = particle->Time;
auto inpos = particle->Pos;
vtkm::VecVariable<vtkm::Vec3f, 2> vectors;
GridEvaluatorStatus status = this->Evaluator.Evaluate(inpos, time, vectors);
velocity = particle->Velocity(vectors, stepLength);
return IntegratorStatus(status);
}
};

@ -49,9 +49,9 @@ public:
IntegralCurveType& integralCurve,
const vtkm::Id& maxSteps) const
{
vtkm::Particle particle = integralCurve.GetParticle(idx);
auto particle = integralCurve.GetParticle(idx);
vtkm::Vec3f currPos = particle.Pos;
//vtkm::Vec3f currPos = particle.Pos;
vtkm::FloatDefault time = particle.Time;
bool tookAnySteps = false;
@ -64,25 +64,24 @@ public:
do
{
vtkm::Vec3f outpos;
auto status = integrator->Step(currPos, time, outpos);
auto status = integrator->Step(&particle, time, outpos);
if (status.CheckOk())
{
integralCurve.StepUpdate(idx, time, outpos);
particle.Pos = outpos;
tookAnySteps = true;
currPos = outpos;
}
//We can't take a step inside spatial boundary.
//Try and take a step just past the boundary.
else if (status.CheckSpatialBounds())
{
IntegratorStatus status2 = integrator->SmallStep(currPos, time, outpos);
IntegratorStatus status2 = integrator->SmallStep(&particle, time, outpos);
if (status2.CheckOk())
{
integralCurve.StepUpdate(idx, time, outpos);
particle.Pos = outpos;
tookAnySteps = true;
currPos = outpos;
//we took a step, so use this status to consider below.
status = status2;
}
@ -90,7 +89,6 @@ public:
status =
IntegratorStatus(true, status2.CheckSpatialBounds(), status2.CheckTemporalBounds());
}
integralCurve.StatusUpdate(idx, status, maxSteps);
} while (integralCurve.CanContinue(idx));
@ -101,7 +99,7 @@ public:
};
template <typename IntegratorType>
template <typename IntegratorType, typename ParticleType>
class ParticleAdvectionWorklet
{
public:
@ -110,14 +108,14 @@ public:
~ParticleAdvectionWorklet() {}
void Run(const IntegratorType& integrator,
vtkm::cont::ArrayHandle<vtkm::Particle>& particles,
vtkm::cont::ArrayHandle<ParticleType>& particles,
vtkm::Id& MaxSteps)
{
using ParticleAdvectWorkletType = vtkm::worklet::particleadvection::ParticleAdvectWorklet;
using ParticleWorkletDispatchType =
typename vtkm::worklet::DispatcherMapField<ParticleAdvectWorkletType>;
using ParticleType = vtkm::worklet::particleadvection::Particles;
using ParticleArrayType = vtkm::worklet::particleadvection::Particles<ParticleType>;
vtkm::Id numSeeds = static_cast<vtkm::Id>(particles.GetNumberOfValues());
//Create and invoke the particle advection.
@ -130,7 +128,7 @@ public:
(void)stack;
#endif // VTKM_CUDA
ParticleType particlesObj(particles, MaxSteps);
ParticleArrayType particlesObj(particles, MaxSteps);
//Invoke particle advection worklet
ParticleWorkletDispatchType particleWorkletDispatch;
@ -174,13 +172,13 @@ public:
} // namespace detail
template <typename IntegratorType>
template <typename IntegratorType, typename ParticleType>
class StreamlineWorklet
{
public:
template <typename PointStorage, typename PointStorage2>
void Run(const IntegratorType& it,
vtkm::cont::ArrayHandle<vtkm::Particle, PointStorage>& particles,
vtkm::cont::ArrayHandle<ParticleType, PointStorage>& particles,
vtkm::Id& MaxSteps,
vtkm::cont::ArrayHandle<vtkm::Vec3f, PointStorage2>& positions,
vtkm::cont::CellSetExplicit<>& polyLines)
@ -188,7 +186,8 @@ public:
using ParticleWorkletDispatchType = typename vtkm::worklet::DispatcherMapField<
vtkm::worklet::particleadvection::ParticleAdvectWorklet>;
using StreamlineType = vtkm::worklet::particleadvection::StateRecordingParticles;
using StreamlineArrayType =
vtkm::worklet::particleadvection::StateRecordingParticles<ParticleType>;
vtkm::cont::ArrayHandle<vtkm::Id> initialStepsTaken;
@ -205,7 +204,7 @@ public:
#endif // VTKM_CUDA
//Run streamline worklet
StreamlineType streamlines(particles, MaxSteps);
StreamlineArrayType streamlines(particles, MaxSteps);
ParticleWorkletDispatchType particleWorkletDispatch;
vtkm::cont::ArrayHandleConstant<vtkm::Id> maxSteps(MaxSteps, numSeeds);
particleWorkletDispatch.Invoke(idxArray, it, streamlines, maxSteps);

@ -26,7 +26,7 @@ namespace worklet
{
namespace particleadvection
{
template <typename Device>
template <typename Device, typename ParticleType>
class ParticleExecutionObject
{
public:
@ -37,7 +37,7 @@ public:
{
}
ParticleExecutionObject(vtkm::cont::ArrayHandle<vtkm::Particle> particleArray,
ParticleExecutionObject(vtkm::cont::ArrayHandle<ParticleType> particleArray,
vtkm::Id maxSteps,
vtkm::cont::Token& token)
{
@ -46,7 +46,7 @@ public:
}
VTKM_EXEC
vtkm::Particle GetParticle(const vtkm::Id& idx) { return this->Particles.Get(idx); }
ParticleType GetParticle(const vtkm::Id& idx) { return this->Particles.Get(idx); }
VTKM_EXEC
void PreStepUpdate(const vtkm::Id& vtkmNotUsed(idx)) {}
@ -54,7 +54,7 @@ public:
VTKM_EXEC
void StepUpdate(const vtkm::Id& idx, vtkm::FloatDefault time, const vtkm::Vec3f& pt)
{
vtkm::Particle p = this->GetParticle(idx);
ParticleType p = this->GetParticle(idx);
p.Pos = pt;
p.Time = time;
p.NumSteps++;
@ -66,7 +66,7 @@ public:
const vtkm::worklet::particleadvection::IntegratorStatus& status,
vtkm::Id maxSteps)
{
vtkm::Particle p = this->GetParticle(idx);
ParticleType p = this->GetParticle(idx);
if (p.NumSteps == maxSteps)
p.Status.SetTerminate();
@ -83,7 +83,7 @@ public:
VTKM_EXEC
bool CanContinue(const vtkm::Id& idx)
{
vtkm::Particle p = this->GetParticle(idx);
ParticleType p = this->GetParticle(idx);
return (p.Status.CheckOk() && !p.Status.CheckTerminate() && !p.Status.CheckSpatialBounds() &&
!p.Status.CheckTemporalBounds());
@ -92,7 +92,7 @@ public:
VTKM_EXEC
void UpdateTookSteps(const vtkm::Id& idx, bool val)
{
vtkm::Particle p = this->GetParticle(idx);
ParticleType p = this->GetParticle(idx);
if (val)
p.Status.SetTookAnySteps();
else
@ -102,26 +102,26 @@ public:
protected:
using ParticlePortal =
typename vtkm::cont::ArrayHandle<vtkm::Particle>::template ExecutionTypes<Device>::Portal;
typename vtkm::cont::ArrayHandle<ParticleType>::template ExecutionTypes<Device>::Portal;
ParticlePortal Particles;
vtkm::Id MaxSteps;
};
template <typename ParticleType>
class Particles : public vtkm::cont::ExecutionObjectBase
{
public:
template <typename Device>
VTKM_CONT vtkm::worklet::particleadvection::ParticleExecutionObject<Device> PrepareForExecution(
Device,
vtkm::cont::Token& token) const
VTKM_CONT vtkm::worklet::particleadvection::ParticleExecutionObject<Device, ParticleType>
PrepareForExecution(Device, vtkm::cont::Token& token) const
{
return vtkm::worklet::particleadvection::ParticleExecutionObject<Device>(
return vtkm::worklet::particleadvection::ParticleExecutionObject<Device, ParticleType>(
this->ParticleArray, this->MaxSteps, token);
}
VTKM_CONT
Particles(vtkm::cont::ArrayHandle<vtkm::Particle>& pArray, vtkm::Id& maxSteps)
Particles(vtkm::cont::ArrayHandle<ParticleType>& pArray, vtkm::Id& maxSteps)
: ParticleArray(pArray)
, MaxSteps(maxSteps)
{
@ -130,18 +130,18 @@ public:
Particles() {}
protected:
vtkm::cont::ArrayHandle<vtkm::Particle> ParticleArray;
vtkm::cont::ArrayHandle<ParticleType> ParticleArray;
vtkm::Id MaxSteps;
};
template <typename Device>
class StateRecordingParticleExecutionObject : public ParticleExecutionObject<Device>
template <typename Device, typename ParticleType>
class StateRecordingParticleExecutionObject : public ParticleExecutionObject<Device, ParticleType>
{
public:
VTKM_EXEC_CONT
StateRecordingParticleExecutionObject()
: ParticleExecutionObject<Device>()
: ParticleExecutionObject<Device, ParticleType>()
, History()
, Length(0)
, StepCount()
@ -149,13 +149,13 @@ public:
{
}
StateRecordingParticleExecutionObject(vtkm::cont::ArrayHandle<vtkm::Particle> pArray,
StateRecordingParticleExecutionObject(vtkm::cont::ArrayHandle<ParticleType> pArray,
vtkm::cont::ArrayHandle<vtkm::Vec3f> historyArray,
vtkm::cont::ArrayHandle<vtkm::Id> validPointArray,
vtkm::cont::ArrayHandle<vtkm::Id> stepCountArray,
vtkm::Id maxSteps,
vtkm::cont::Token& token)
: ParticleExecutionObject<Device>(pArray, maxSteps, token)
: ParticleExecutionObject<Device, ParticleType>(pArray, maxSteps, token)
, Length(maxSteps + 1)
{
vtkm::Id numPos = pArray.GetNumberOfValues();
@ -167,7 +167,7 @@ public:
VTKM_EXEC
void PreStepUpdate(const vtkm::Id& idx)
{
vtkm::Particle p = this->ParticleExecutionObject<Device>::GetParticle(idx);
ParticleType p = this->ParticleExecutionObject<Device, ParticleType>::GetParticle(idx);
if (p.NumSteps == 0)
{
vtkm::Id loc = idx * Length;
@ -180,7 +180,7 @@ public:
VTKM_EXEC
void StepUpdate(const vtkm::Id& idx, vtkm::FloatDefault time, const vtkm::Vec3f& pt)
{
this->ParticleExecutionObject<Device>::StepUpdate(idx, time, pt);
this->ParticleExecutionObject<Device, ParticleType>::StepUpdate(idx, time, pt);
//local step count.
vtkm::Id stepCount = this->StepCount.Get(idx);
@ -203,6 +203,7 @@ protected:
IdPortal ValidPoint;
};
template <typename ParticleType>
class StateRecordingParticles : vtkm::cont::ExecutionObjectBase
{
public:
@ -218,10 +219,12 @@ public:
template <typename Device>
VTKM_CONT vtkm::worklet::particleadvection::StateRecordingParticleExecutionObject<Device>
PrepareForExecution(Device, vtkm::cont::Token& token) const
VTKM_CONT
vtkm::worklet::particleadvection::StateRecordingParticleExecutionObject<Device, ParticleType>
PrepareForExecution(Device, vtkm::cont::Token& token) const
{
return vtkm::worklet::particleadvection::StateRecordingParticleExecutionObject<Device>(
return vtkm::worklet::particleadvection::StateRecordingParticleExecutionObject<Device,
ParticleType>(
this->ParticleArray,
this->HistoryArray,
this->ValidPointArray,
@ -230,7 +233,7 @@ public:
token);
}
VTKM_CONT
StateRecordingParticles(vtkm::cont::ArrayHandle<vtkm::Particle>& pArray, const vtkm::Id& maxSteps)
StateRecordingParticles(vtkm::cont::ArrayHandle<ParticleType>& pArray, const vtkm::Id& maxSteps)
: MaxSteps(maxSteps)
, ParticleArray(pArray)
{
@ -246,7 +249,7 @@ public:
}
VTKM_CONT
StateRecordingParticles(vtkm::cont::ArrayHandle<vtkm::Particle>& pArray,
StateRecordingParticles(vtkm::cont::ArrayHandle<ParticleType>& pArray,
vtkm::cont::ArrayHandle<vtkm::Vec3f>& historyArray,
vtkm::cont::ArrayHandle<vtkm::Id>& validPointArray,
vtkm::Id& maxSteps)
@ -266,7 +269,7 @@ public:
protected:
vtkm::cont::ArrayHandle<vtkm::Vec3f> HistoryArray;
vtkm::Id MaxSteps;
vtkm::cont::ArrayHandle<vtkm::Particle> ParticleArray;
vtkm::cont::ArrayHandle<ParticleType> ParticleArray;
vtkm::cont::ArrayHandle<vtkm::Id> StepCountArray;
vtkm::cont::ArrayHandle<vtkm::Id> ValidPointArray;
};

@ -21,13 +21,13 @@ namespace worklet
namespace particleadvection
{
template <typename DeviceAdapter, typename FieldArrayType>
template <typename DeviceAdapter, typename FieldType>
class ExecutionTemporalGridEvaluator
{
private:
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldArrayType>;
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using ExecutionGridEvaluator =
vtkm::worklet::particleadvection::ExecutionGridEvaluator<DeviceAdapter, FieldArrayType>;
vtkm::worklet::particleadvection::ExecutionGridEvaluator<DeviceAdapter, FieldType>;
public:
VTKM_CONT
@ -70,9 +70,9 @@ public:
}
template <typename Point>
VTKM_EXEC GridEvaluatorStatus Evaluate(const Point& pos,
VTKM_EXEC GridEvaluatorStatus Evaluate(const Point& particle,
vtkm::FloatDefault time,
Point& out) const
vtkm::VecVariable<Point, 2>& out) const
{
// Validate time is in bounds for the current two slices.
GridEvaluatorStatus status;
@ -84,17 +84,21 @@ public:
return status;
}
Point one, two;
status = this->EvaluatorOne.Evaluate(pos, one);
vtkm::VecVariable<Point, 2> e1, e2;
status = this->EvaluatorOne.Evaluate(particle, e1);
if (status.CheckFail())
return status;
status = this->EvaluatorTwo.Evaluate(pos, two);
status = this->EvaluatorTwo.Evaluate(particle, e2);
if (status.CheckFail())
return status;
// LERP between the two values of calculated fields to obtain the new value
vtkm::FloatDefault proportion = (time - this->TimeOne) / this->TimeDiff;
out = vtkm::Lerp(one, two, proportion);
VTKM_ASSERT(e1.GetNumberOfComponents() != 0 &&
e1.GetNumberOfComponents() == e2.GetNumberOfComponents());
out = vtkm::VecVariable<Point, 2>{};
for (vtkm::IdComponent index = 0; index < e1.GetNumberOfComponents(); ++index)
out.Append(vtkm::Lerp(e1[index], e2[index], proportion));
status.SetOk();
return status;
@ -108,11 +112,11 @@ private:
vtkm::FloatDefault TimeDiff;
};
template <typename FieldArrayType>
template <typename FieldType>
class TemporalGridEvaluator : public vtkm::cont::ExecutionObjectBase
{
private:
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldArrayType>;
using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
public:
VTKM_CONT TemporalGridEvaluator() = default;
@ -130,11 +134,11 @@ public:
VTKM_CONT TemporalGridEvaluator(const vtkm::cont::CoordinateSystem& coordinatesOne,
const vtkm::cont::DynamicCellSet& cellsetOne,
const FieldArrayType& fieldOne,
const FieldType& fieldOne,
const vtkm::FloatDefault timeOne,
const vtkm::cont::CoordinateSystem& coordinatesTwo,
const vtkm::cont::DynamicCellSet& cellsetTwo,
const FieldArrayType& fieldTwo,
const FieldType& fieldTwo,
const vtkm::FloatDefault timeTwo)
: EvaluatorOne(GridEvaluator(coordinatesOne, cellsetOne, fieldOne))
, EvaluatorTwo(GridEvaluator(coordinatesTwo, cellsetTwo, fieldTwo))
@ -144,11 +148,11 @@ public:
}
template <typename DeviceAdapter>
VTKM_CONT ExecutionTemporalGridEvaluator<DeviceAdapter, FieldArrayType> PrepareForExecution(
VTKM_CONT ExecutionTemporalGridEvaluator<DeviceAdapter, FieldType> PrepareForExecution(
DeviceAdapter,
vtkm::cont::Token& token) const
{
return ExecutionTemporalGridEvaluator<DeviceAdapter, FieldArrayType>(
return ExecutionTemporalGridEvaluator<DeviceAdapter, FieldType>(
this->EvaluatorOne, this->TimeOne, this->EvaluatorTwo, this->TimeTwo, token);
}

@ -18,6 +18,7 @@
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/worklet/ParticleAdvection.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/GridEvaluators.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
@ -93,7 +94,7 @@ vtkm::FloatDefault vecData[125 * 3] = {
};
}
void GenerateRandomParticles(std::vector<vtkm::Particle>& points,
void GenerateRandomParticles(std::vector<vtkm::Massless>& points,
const std::size_t N,
const vtkm::Bounds& bounds,
const std::size_t seed = 314)
@ -114,7 +115,7 @@ void GenerateRandomParticles(std::vector<vtkm::Particle>& points,
p[0] = static_cast<vtkm::FloatDefault>(bounds.X.Min + rx * bounds.X.Length());
p[1] = static_cast<vtkm::FloatDefault>(bounds.Y.Min + ry * bounds.Y.Length());
p[2] = static_cast<vtkm::FloatDefault>(bounds.Z.Min + rz * bounds.Z.Length());
points.push_back(vtkm::Particle(p, static_cast<vtkm::Id>(i)));
points.push_back(vtkm::Massless(p, static_cast<vtkm::Id>(i)));
}
}
@ -292,18 +293,20 @@ public:
using ExecutionSignature = void(_1, _2, _3, _4);
template <typename EvaluatorType>
VTKM_EXEC void operator()(vtkm::Particle& pointIn,
VTKM_EXEC void operator()(vtkm::Massless& pointIn,
const EvaluatorType& evaluator,
vtkm::worklet::particleadvection::GridEvaluatorStatus& status,
vtkm::Vec3f& pointOut) const
{
status = evaluator.Evaluate(pointIn.Pos, pointOut);
vtkm::VecVariable<vtkm::Vec3f, 2> values;
status = evaluator.Evaluate(pointIn.Pos, values);
pointOut = values[0];
}
};
template <typename EvalType>
void ValidateEvaluator(const EvalType& eval,
const std::vector<vtkm::Particle>& pointIns,
const std::vector<vtkm::Massless>& pointIns,
const vtkm::Vec3f& vec,
const std::string& msg)
{
@ -312,7 +315,7 @@ void ValidateEvaluator(const EvalType& eval,
using Status = vtkm::worklet::particleadvection::GridEvaluatorStatus;
EvalTester evalTester;
EvalTesterDispatcher evalTesterDispatcher(evalTester);
vtkm::cont::ArrayHandle<vtkm::Particle> pointsHandle = vtkm::cont::make_ArrayHandle(pointIns);
vtkm::cont::ArrayHandle<vtkm::Massless> pointsHandle = vtkm::cont::make_ArrayHandle(pointIns);
vtkm::Id numPoints = pointsHandle.GetNumberOfValues();
vtkm::cont::ArrayHandle<Status> evalStatus;
vtkm::cont::ArrayHandle<vtkm::Vec3f> evalResults;
@ -339,22 +342,22 @@ public:
using ExecutionSignature = void(_1, _2, _3, _4);
template <typename IntegratorType>
VTKM_EXEC void operator()(vtkm::Particle& pointIn,
VTKM_EXEC void operator()(vtkm::Massless& pointIn,
const IntegratorType* integrator,
vtkm::worklet::particleadvection::IntegratorStatus& status,
vtkm::Vec3f& pointOut) const
{
vtkm::FloatDefault time = 0;
status = integrator->Step(pointIn.Pos, time, pointOut);
status = integrator->Step(&pointIn, time, pointOut);
if (status.CheckSpatialBounds())
status = integrator->SmallStep(pointIn.Pos, time, pointOut);
status = integrator->SmallStep(&pointIn, time, pointOut);
}
};
template <typename IntegratorType>
void ValidateIntegrator(const IntegratorType& integrator,
const std::vector<vtkm::Particle>& pointIns,
const std::vector<vtkm::Massless>& pointIns,
const std::vector<vtkm::Vec3f>& expStepResults,
const std::string& msg)
{
@ -387,7 +390,7 @@ void ValidateIntegrator(const IntegratorType& integrator,
template <typename IntegratorType>
void ValidateIntegratorForBoundary(const vtkm::Bounds& bounds,
const IntegratorType& integrator,
const std::vector<vtkm::Particle>& pointIns,
const std::vector<vtkm::Massless>& pointIns,
const std::string& msg)
{
using IntegratorTester = TestIntegratorWorklet;
@ -417,7 +420,8 @@ void ValidateIntegratorForBoundary(const vtkm::Bounds& bounds,
void TestEvaluators()
{
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
std::vector<vtkm::Vec3f> vecs;
@ -451,10 +455,11 @@ void TestEvaluators()
vtkm::cont::ArrayHandle<vtkm::Vec3f> vecField;
CreateConstantVectorField(dim[0] * dim[1] * dim[2], vec, vecField);
FieldType velocities(vecField);
//vtkm::FloatDefault stepSize = 0.01f;
vtkm::FloatDefault stepSize = 0.1f;
std::vector<vtkm::Particle> pointIns;
std::vector<vtkm::Massless> pointIns;
std::vector<vtkm::Vec3f> stepResult;
//Generate points 2 steps inside the bounding box.
@ -491,12 +496,12 @@ void TestEvaluators()
// of the velocity field
// All velocities are in the +ve direction.
std::vector<vtkm::Particle> boundaryPoints;
std::vector<vtkm::Massless> boundaryPoints;
GenerateRandomParticles(boundaryPoints, 10, forBoundary, 919);
for (auto& ds : dataSets)
{
GridEvalType gridEval(ds.GetCoordinateSystem(), ds.GetCellSet(), vecField);
GridEvalType gridEval(ds.GetCoordinateSystem(), ds.GetCellSet(), velocities);
ValidateEvaluator(gridEval, pointIns, vec, "grid evaluator");
RK4Type rk4(gridEval, stepSize);
@ -508,9 +513,10 @@ void TestEvaluators()
}
}
void ValidateParticleAdvectionResult(const vtkm::worklet::ParticleAdvectionResult& res,
vtkm::Id nSeeds,
vtkm::Id maxSteps)
void ValidateParticleAdvectionResult(
const vtkm::worklet::ParticleAdvectionResult<vtkm::Massless>& res,
vtkm::Id nSeeds,
vtkm::Id maxSteps)
{
VTKM_TEST_ASSERT(res.Particles.GetNumberOfValues() == nSeeds,
"Number of output particles does not match input.");
@ -528,7 +534,7 @@ void ValidateParticleAdvectionResult(const vtkm::worklet::ParticleAdvectionResul
}
}
void ValidateStreamlineResult(const vtkm::worklet::StreamlineResult& res,
void ValidateStreamlineResult(const vtkm::worklet::StreamlineResult<vtkm::Massless>& res,
vtkm::Id nSeeds,
vtkm::Id maxSteps)
{
@ -547,7 +553,8 @@ void ValidateStreamlineResult(const vtkm::worklet::StreamlineResult& res,
void TestIntegrators()
{
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
const vtkm::Id3 dims(5, 5, 5);
const vtkm::Bounds bounds(0., 1., 0., 1., .0, .1);
@ -562,15 +569,16 @@ void TestIntegrators()
for (vtkm::Id i = 0; i < nElements; i++)
fieldData.push_back(vtkm::Vec3f(0., 0., 1.));
FieldHandle fieldValues = vtkm::cont::make_ArrayHandle(fieldData);
FieldType velocities(fieldValues);
GridEvalType eval(dataset.GetCoordinateSystem(), dataset.GetCellSet(), fieldValues);
GridEvalType eval(dataset.GetCoordinateSystem(), dataset.GetCellSet(), velocities);
//Generate three random points.
std::vector<vtkm::Particle> points;
std::vector<vtkm::Massless> points;
GenerateRandomParticles(points, 3, bounds);
vtkm::worklet::ParticleAdvection pa;
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
{
auto seeds = vtkm::cont::make_ArrayHandle(points, vtkm::CopyFlag::On);
using IntegratorType = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
@ -590,7 +598,8 @@ void TestIntegrators()
void TestParticleWorkletsWithDataSetTypes()
{
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
vtkm::FloatDefault stepSize = 0.01f;
@ -608,6 +617,7 @@ void TestParticleWorkletsWithDataSetTypes()
}
vtkm::cont::ArrayHandle<vtkm::Vec3f> fieldArray;
fieldArray = vtkm::cont::make_ArrayHandle(field);
FieldType velocities(fieldArray);
std::vector<vtkm::Bounds> bounds;
bounds.push_back(vtkm::Bounds(0, 10, 0, 10, 0, 10));
@ -627,9 +637,9 @@ void TestParticleWorkletsWithDataSetTypes()
dataSets.push_back(CreateWeirdnessFromStructuredDataSet(dataSets[0], DataSetOption::EXPLICIT));
//Generate three random points.
std::vector<vtkm::Particle> pts;
std::vector<vtkm::Massless> pts;
GenerateRandomParticles(pts, 3, bound, 111);
std::vector<vtkm::Particle> pts2 = pts;
std::vector<vtkm::Massless> pts2 = pts;
vtkm::Id nSeeds = static_cast<vtkm::Id>(pts.size());
std::vector<vtkm::Id> stepsTaken = { 10, 20, 600 };
@ -638,7 +648,7 @@ void TestParticleWorkletsWithDataSetTypes()
for (auto& ds : dataSets)
{
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), fieldArray);
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), velocities);
RK4Type rk4(eval, stepSize);
//Do 4 tests on each dataset.
@ -649,7 +659,7 @@ void TestParticleWorkletsWithDataSetTypes()
if (i < 2)
{
vtkm::worklet::ParticleAdvection pa;
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
if (i == 0)
{
auto seeds = vtkm::cont::make_ArrayHandle(pts, vtkm::CopyFlag::On);
@ -665,7 +675,7 @@ void TestParticleWorkletsWithDataSetTypes()
else
{
vtkm::worklet::Streamline s;
vtkm::worklet::StreamlineResult res;
vtkm::worklet::StreamlineResult<vtkm::Massless> res;
if (i == 2)
{
auto seeds = vtkm::cont::make_ArrayHandle(pts, vtkm::CopyFlag::On);
@ -695,22 +705,24 @@ void TestParticleStatus()
for (vtkm::Id i = 0; i < nElements; i++)
field.push_back(vtkm::Vec3f(1, 0, 0));
vtkm::cont::ArrayHandle<vtkm::Vec3f> fieldArray;
fieldArray = vtkm::cont::make_ArrayHandle(field);
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
vtkm::Id maxSteps = 1000;
vtkm::FloatDefault stepSize = 0.01f;
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), fieldArray);
FieldHandle fieldArray;
fieldArray = vtkm::cont::make_ArrayHandle(field);
FieldType velocities(fieldArray);
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), velocities);
RK4Type rk4(eval, stepSize);
vtkm::worklet::ParticleAdvection pa;
std::vector<vtkm::Particle> pts;
pts.push_back(vtkm::Particle(vtkm::Vec3f(.5, .5, .5), 0));
pts.push_back(vtkm::Particle(vtkm::Vec3f(-1, -1, -1), 1));
std::vector<vtkm::Massless> pts;
pts.push_back(vtkm::Massless(vtkm::Vec3f(.5, .5, .5), 0));
pts.push_back(vtkm::Massless(vtkm::Vec3f(-1, -1, -1), 1));
auto seedsArray = vtkm::cont::make_ArrayHandle(pts, vtkm::CopyFlag::On);
pa.Run(rk4, seedsArray, maxSteps);
auto portal = seedsArray.ReadPortal();
@ -724,7 +736,8 @@ void TestParticleStatus()
void TestWorkletsBasic()
{
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using RK4Type = vtkm::worklet::particleadvection::RK4Integrator<GridEvalType>;
vtkm::FloatDefault stepSize = 0.01f;
@ -736,13 +749,14 @@ void TestWorkletsBasic()
for (vtkm::Id i = 0; i < nElements; i++)
field.push_back(vtkm::Normal(vecDir));
vtkm::cont::ArrayHandle<vtkm::Vec3f> fieldArray;
FieldHandle fieldArray;
fieldArray = vtkm::cont::make_ArrayHandle(field);
FieldType velocities(fieldArray);
vtkm::Bounds bounds(0, 1, 0, 1, 0, 1);
auto ds = CreateUniformDataSet(bounds, dims);
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), fieldArray);
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), velocities);
RK4Type rk4(eval, stepSize);
vtkm::Id maxSteps = 83;
@ -751,7 +765,7 @@ void TestWorkletsBasic()
for (auto w : workletTypes)
{
std::vector<vtkm::Particle> particles;
std::vector<vtkm::Massless> particles;
std::vector<vtkm::Vec3f> pts, samplePts, endPts;
vtkm::FloatDefault X = static_cast<vtkm::FloatDefault>(.1);
vtkm::FloatDefault Y = static_cast<vtkm::FloatDefault>(.1);
@ -767,7 +781,7 @@ void TestWorkletsBasic()
for (std::size_t i = 0; i < pts.size(); i++, id++)
{
vtkm::Vec3f p = pts[i];
particles.push_back(vtkm::Particle(p, id));
particles.push_back(vtkm::Massless(p, id));
samplePts.push_back(p);
for (vtkm::Id j = 0; j < maxSteps; j++)
{
@ -782,7 +796,7 @@ void TestWorkletsBasic()
if (w == "particleAdvection")
{
vtkm::worklet::ParticleAdvection pa;
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
res = pa.Run(rk4, seedsArray, maxSteps);
@ -806,7 +820,7 @@ void TestWorkletsBasic()
else if (w == "streamline")
{
vtkm::worklet::Streamline s;
vtkm::worklet::StreamlineResult res;
vtkm::worklet::StreamlineResult<vtkm::Massless> res;
res = s.Run(rk4, seedsArray, maxSteps);
@ -880,6 +894,7 @@ void TestParticleAdvectionFile(const std::string& fname,
vtkm::Id maxSteps,
const std::vector<vtkm::Vec3f>& endPts)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing particle advection on file " << fname);
vtkm::io::VTKDataSetReader reader(fname);
vtkm::cont::DataSet ds;
@ -897,8 +912,9 @@ void TestParticleAdvectionFile(const std::string& fname,
VTKM_TEST_FAIL(message.c_str());
}
using FieldHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f_32>;
using GridEvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
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>;
VTKM_TEST_ASSERT(ds.HasField("vec"));
@ -907,6 +923,7 @@ void TestParticleAdvectionFile(const std::string& fname,
if (!fieldData.IsType<FieldHandle>())
{
ds.PrintSummary(std::cout);
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"The field data is of type "
<< vtkm::cont::TypeToString<decltype(fieldData)>()
@ -914,22 +931,21 @@ void TestParticleAdvectionFile(const std::string& fname,
VTKM_TEST_FAIL("No field with correct type found.");
}
FieldHandle fieldArray = fieldData.Cast<FieldHandle>();
GridEvalType eval(ds.GetCoordinateSystem(), ds.GetCellSet(), fieldArray);
RK4Type rk4(eval, stepSize);
for (int i = 0; i < 2; i++)
{
std::vector<vtkm::Particle> seeds;
std::vector<vtkm::Massless> seeds;
for (size_t j = 0; j < pts.size(); j++)
seeds.push_back(vtkm::Particle(pts[j], static_cast<vtkm::Id>(j)));
seeds.push_back(vtkm::Massless(pts[j], static_cast<vtkm::Id>(j)));
auto seedArray = vtkm::cont::make_ArrayHandle(seeds);
if (i == 0)
{
vtkm::worklet::ParticleAdvection pa;
vtkm::worklet::ParticleAdvectionResult res;
vtkm::worklet::ParticleAdvectionResult<vtkm::Massless> res;
res = pa.Run(rk4, seedArray, maxSteps);
ValidateResult(res, maxSteps, endPts);
@ -937,7 +953,7 @@ void TestParticleAdvectionFile(const std::string& fname,
else if (i == 1)
{
vtkm::worklet::Streamline s;
vtkm::worklet::StreamlineResult res;
vtkm::worklet::StreamlineResult<vtkm::Massless> res;
res = s.Run(rk4, seedArray, maxSteps);
ValidateResult(res, maxSteps, endPts);
@ -953,6 +969,7 @@ void TestParticleAdvection()
TestWorkletsBasic();
TestParticleWorkletsWithDataSetTypes();
/*
std::string basePath = vtkm::cont::testing::Testing::GetTestDataBasePath();
//Fusion test.
@ -981,6 +998,7 @@ void TestParticleAdvection()
vtkm::FloatDefault fishStep = 0.001f;
std::string fishFile = basePath + "/rectilinear/fishtank.vtk";
TestParticleAdvectionFile(fishFile, fishPts, fishStep, 100, fishEndPts);
*/
}
int UnitTestParticleAdvection(int argc, char* argv[])

@ -9,6 +9,7 @@
//============================================================================
#include <typeinfo>
#include <vtkm/VecVariable.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
@ -17,6 +18,7 @@
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/worklet/ParticleAdvection.h>
#include <vtkm/worklet/particleadvection/Field.h>
#include <vtkm/worklet/particleadvection/Integrators.h>
#include <vtkm/worklet/particleadvection/Particles.h>
#include <vtkm/worklet/particleadvection/TemporalGridEvaluators.h>
@ -48,18 +50,21 @@ public:
using ExecutionSignature = void(_1, _2, _3, _4);
template <typename EvaluatorType>
VTKM_EXEC void operator()(vtkm::Particle& pointIn,
VTKM_EXEC void operator()(vtkm::Massless& pointIn,
const EvaluatorType& evaluator,
vtkm::worklet::particleadvection::GridEvaluatorStatus& status,
vtkm::Vec3f& pointOut) const
{
status = evaluator.Evaluate(pointIn.Pos, 0.5f, pointOut);
vtkm::VecVariable<vtkm::Vec3f, 2> values;
status = evaluator.Evaluate(pointIn.Pos, 0.5f, values);
if (values.GetNumberOfComponents() > 0)
pointOut = values[0];
}
};
template <typename EvalType>
void ValidateEvaluator(const EvalType& eval,
const vtkm::cont::ArrayHandle<vtkm::Particle>& pointIns,
const vtkm::cont::ArrayHandle<vtkm::Massless>& pointIns,
const vtkm::cont::ArrayHandle<vtkm::Vec3f>& validity,
const std::string& msg)
{
@ -114,13 +119,13 @@ vtkm::Vec3f RandomPt(const vtkm::Bounds& bounds)
void GeneratePoints(const vtkm::Id numOfEntries,
const vtkm::Bounds& bounds,
vtkm::cont::ArrayHandle<vtkm::Particle>& pointIns)
vtkm::cont::ArrayHandle<vtkm::Massless>& pointIns)
{
pointIns.Allocate(numOfEntries);
auto writePortal = pointIns.WritePortal();
for (vtkm::Id index = 0; index < numOfEntries; index++)
{
vtkm::Particle particle(RandomPt(bounds), index);
vtkm::Massless particle(RandomPt(bounds), index);
writePortal.Set(index, particle);
}
}
@ -144,8 +149,9 @@ void TestTemporalEvaluators()
using ScalarType = vtkm::FloatDefault;
using PointType = vtkm::Vec<ScalarType, 3>;
using FieldHandle = vtkm::cont::ArrayHandle<PointType>;
using EvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldHandle>;
using TemporalEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<FieldHandle>;
using FieldType = vtkm::worklet::particleadvection::VelocityField<FieldHandle>;
using EvalType = vtkm::worklet::particleadvection::GridEvaluator<FieldType>;
using TemporalEvalType = vtkm::worklet::particleadvection::TemporalGridEvaluator<FieldType>;
// Create Datasets
vtkm::Id3 dims(5, 5, 5);
@ -159,14 +165,16 @@ void TestTemporalEvaluators()
vtkm::cont::ArrayHandle<PointType> alongX, alongZ;
CreateConstantVectorField(125, X, alongX);
CreateConstantVectorField(125, Z, alongZ);
FieldType velocityX(alongX);
FieldType velocityZ(alongZ);
// Send them to test
EvalType evalOne(sliceOne.GetCoordinateSystem(), sliceOne.GetCellSet(), alongX);
EvalType evalTwo(sliceTwo.GetCoordinateSystem(), sliceTwo.GetCellSet(), alongZ);
EvalType evalOne(sliceOne.GetCoordinateSystem(), sliceOne.GetCellSet(), velocityX);
EvalType evalTwo(sliceTwo.GetCoordinateSystem(), sliceTwo.GetCellSet(), velocityZ);
// Test data : populate with meaningful values
vtkm::Id numValues = 10;
vtkm::cont::ArrayHandle<vtkm::Particle> pointIns;
vtkm::cont::ArrayHandle<vtkm::Massless> pointIns;
vtkm::cont::ArrayHandle<vtkm::Vec3f> validity;
GeneratePoints(numValues, bounds, pointIns);
GenerateValidity(numValues, validity, X, Z);