2017-04-18 20:49:03 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
2019-04-15 23:24:21 +00:00
|
|
|
//
|
2017-04-18 20:49:03 +00:00
|
|
|
// 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.
|
|
|
|
//============================================================================
|
|
|
|
|
2017-07-08 19:54:44 +00:00
|
|
|
#ifndef vtk_m_worklet_particleadvection_ParticleAdvectionWorklets_h
|
|
|
|
#define vtk_m_worklet_particleadvection_ParticleAdvectionWorklets_h
|
2017-04-18 20:49:03 +00:00
|
|
|
|
|
|
|
#include <vtkm/Types.h>
|
2018-08-30 15:53:18 +00:00
|
|
|
#include <vtkm/cont/Algorithm.h>
|
2018-07-08 01:19:39 +00:00
|
|
|
#include <vtkm/cont/ArrayCopy.h>
|
2017-04-18 20:49:03 +00:00
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
2017-07-21 18:37:20 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleCast.h>
|
2017-04-18 20:49:03 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleCounting.h>
|
2017-08-29 12:35:29 +00:00
|
|
|
#include <vtkm/cont/CellSetExplicit.h>
|
2021-08-18 20:47:40 +00:00
|
|
|
#include <vtkm/cont/ConvertNumComponentsToOffsets.h>
|
2018-05-15 18:35:29 +00:00
|
|
|
#include <vtkm/cont/ExecutionObjectBase.h>
|
2017-04-18 20:49:03 +00:00
|
|
|
|
2019-09-17 20:24:44 +00:00
|
|
|
#include <vtkm/Particle.h>
|
2021-02-08 23:24:20 +00:00
|
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
2017-04-18 20:49:03 +00:00
|
|
|
#include <vtkm/worklet/particleadvection/Particles.h>
|
2021-03-23 06:00:36 +00:00
|
|
|
#include <vtkm/worklet/particleadvection/Stepper.h>
|
2017-04-18 20:49:03 +00:00
|
|
|
|
2020-06-16 12:54:01 +00:00
|
|
|
#ifdef VTKM_CUDA
|
|
|
|
#include <vtkm/cont/cuda/internal/ScopedCudaStackSize.h>
|
|
|
|
#endif
|
|
|
|
|
2017-07-07 17:36:31 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace worklet
|
|
|
|
{
|
|
|
|
namespace particleadvection
|
|
|
|
{
|
2017-04-18 20:49:03 +00:00
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
class ParticleAdvectWorklet : public vtkm::worklet::WorkletMapField
|
2019-09-18 18:08:26 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-10-01 17:33:12 +00:00
|
|
|
using ControlSignature = void(FieldIn idx,
|
|
|
|
ExecObject integrator,
|
2019-12-04 16:52:08 +00:00
|
|
|
ExecObject integralCurve,
|
2019-10-01 17:33:12 +00:00
|
|
|
FieldIn maxSteps);
|
2019-12-04 16:52:08 +00:00
|
|
|
using ExecutionSignature = void(_1 idx, _2 integrator, _3 integralCurve, _4 maxSteps);
|
2019-10-01 17:33:12 +00:00
|
|
|
using InputDomain = _1;
|
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
template <typename IntegratorType, typename IntegralCurveType>
|
2019-10-01 17:33:12 +00:00
|
|
|
VTKM_EXEC void operator()(const vtkm::Id& idx,
|
2021-03-23 06:00:36 +00:00
|
|
|
const IntegratorType& integrator,
|
2019-12-04 16:52:08 +00:00
|
|
|
IntegralCurveType& integralCurve,
|
2019-09-18 18:08:26 +00:00
|
|
|
const vtkm::Id& maxSteps) const
|
|
|
|
{
|
2020-07-21 01:15:46 +00:00
|
|
|
auto particle = integralCurve.GetParticle(idx);
|
2019-09-18 18:08:26 +00:00
|
|
|
vtkm::FloatDefault time = particle.Time;
|
|
|
|
bool tookAnySteps = false;
|
2019-10-01 17:33:12 +00:00
|
|
|
|
|
|
|
//the integrator status needs to be more robust:
|
|
|
|
// 1. you could have success AND at temporal boundary.
|
|
|
|
// 2. could you have success AND at spatial?
|
|
|
|
// 3. all three?
|
2019-12-04 16:52:08 +00:00
|
|
|
integralCurve.PreStepUpdate(idx);
|
2019-10-01 17:33:12 +00:00
|
|
|
do
|
2019-09-18 18:08:26 +00:00
|
|
|
{
|
2021-09-02 00:22:51 +00:00
|
|
|
particle = integralCurve.GetParticle(idx);
|
2019-12-04 16:52:08 +00:00
|
|
|
vtkm::Vec3f outpos;
|
2021-03-23 06:00:36 +00:00
|
|
|
auto status = integrator.Step(particle, time, outpos);
|
2019-10-01 17:33:12 +00:00
|
|
|
if (status.CheckOk())
|
2019-09-18 18:08:26 +00:00
|
|
|
{
|
2021-09-02 00:22:51 +00:00
|
|
|
integralCurve.StepUpdate(idx, particle, time, outpos);
|
2019-09-18 18:08:26 +00:00
|
|
|
tookAnySteps = true;
|
|
|
|
}
|
|
|
|
|
2019-10-01 17:33:12 +00:00
|
|
|
//We can't take a step inside spatial boundary.
|
|
|
|
//Try and take a step just past the boundary.
|
|
|
|
else if (status.CheckSpatialBounds())
|
|
|
|
{
|
2021-03-23 06:00:36 +00:00
|
|
|
status = integrator.SmallStep(particle, time, outpos);
|
2020-10-19 20:46:48 +00:00
|
|
|
if (status.CheckOk())
|
2019-09-18 18:08:26 +00:00
|
|
|
{
|
2021-09-02 00:22:51 +00:00
|
|
|
integralCurve.StepUpdate(idx, particle, time, outpos);
|
2019-10-01 17:33:12 +00:00
|
|
|
tookAnySteps = true;
|
2019-09-18 18:08:26 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-04 16:52:08 +00:00
|
|
|
integralCurve.StatusUpdate(idx, status, maxSteps);
|
|
|
|
} while (integralCurve.CanContinue(idx));
|
2019-10-01 17:33:12 +00:00
|
|
|
|
|
|
|
//Mark if any steps taken
|
2019-12-04 16:52:08 +00:00
|
|
|
integralCurve.UpdateTookSteps(idx, tookAnySteps);
|
2017-07-07 17:36:31 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-07-12 02:22:28 +00:00
|
|
|
|
2020-07-21 01:15:46 +00:00
|
|
|
template <typename IntegratorType, typename ParticleType>
|
2017-07-08 19:54:44 +00:00
|
|
|
class ParticleAdvectionWorklet
|
2017-04-18 20:49:03 +00:00
|
|
|
{
|
|
|
|
public:
|
2018-07-08 01:19:39 +00:00
|
|
|
VTKM_EXEC_CONT ParticleAdvectionWorklet() {}
|
2017-04-18 20:49:03 +00:00
|
|
|
|
2017-07-08 19:54:44 +00:00
|
|
|
~ParticleAdvectionWorklet() {}
|
2017-07-07 17:36:31 +00:00
|
|
|
|
2018-07-08 01:19:39 +00:00
|
|
|
void Run(const IntegratorType& integrator,
|
2020-07-21 01:15:46 +00:00
|
|
|
vtkm::cont::ArrayHandle<ParticleType>& particles,
|
2019-12-04 16:52:08 +00:00
|
|
|
vtkm::Id& MaxSteps)
|
2017-07-07 17:36:31 +00:00
|
|
|
{
|
2019-12-04 16:52:08 +00:00
|
|
|
|
2018-07-11 15:47:32 +00:00
|
|
|
using ParticleAdvectWorkletType = vtkm::worklet::particleadvection::ParticleAdvectWorklet;
|
2017-09-14 15:16:29 +00:00
|
|
|
using ParticleWorkletDispatchType =
|
2018-08-28 20:36:50 +00:00
|
|
|
typename vtkm::worklet::DispatcherMapField<ParticleAdvectWorkletType>;
|
2020-07-21 01:15:46 +00:00
|
|
|
using ParticleArrayType = vtkm::worklet::particleadvection::Particles<ParticleType>;
|
2017-05-25 21:16:09 +00:00
|
|
|
|
2019-09-18 18:08:26 +00:00
|
|
|
vtkm::Id numSeeds = static_cast<vtkm::Id>(particles.GetNumberOfValues());
|
|
|
|
//Create and invoke the particle advection.
|
|
|
|
vtkm::cont::ArrayHandleConstant<vtkm::Id> maxSteps(MaxSteps, numSeeds);
|
2019-10-01 17:33:12 +00:00
|
|
|
vtkm::cont::ArrayHandleIndex idxArray(numSeeds);
|
2019-09-18 18:08:26 +00:00
|
|
|
|
2021-07-29 18:47:29 +00:00
|
|
|
// TODO: The particle advection sometimes behaves incorrectly on CUDA if the stack size
|
|
|
|
// is not changed thusly. This is concerning as the compiler should be able to determine
|
|
|
|
// staticly the required stack depth. What is even more concerning is that the runtime
|
|
|
|
// does not report a stack overflow. Rather, the worklet just silently reports the wrong
|
|
|
|
// value. Until we determine the root cause, other problems may pop up.
|
2019-09-18 18:08:26 +00:00
|
|
|
#ifdef VTKM_CUDA
|
|
|
|
// This worklet needs some extra space on CUDA.
|
2020-06-16 12:54:01 +00:00
|
|
|
vtkm::cont::cuda::internal::ScopedCudaStackSize stack(16 * 1024);
|
2019-09-18 18:08:26 +00:00
|
|
|
(void)stack;
|
|
|
|
#endif // VTKM_CUDA
|
|
|
|
|
2020-07-21 01:15:46 +00:00
|
|
|
ParticleArrayType particlesObj(particles, MaxSteps);
|
2019-12-04 16:52:08 +00:00
|
|
|
|
2019-09-18 18:08:26 +00:00
|
|
|
//Invoke particle advection worklet
|
|
|
|
ParticleWorkletDispatchType particleWorkletDispatch;
|
2019-12-04 16:52:08 +00:00
|
|
|
|
|
|
|
particleWorkletDispatch.Invoke(idxArray, integrator, particlesObj, maxSteps);
|
2019-09-18 18:08:26 +00:00
|
|
|
}
|
2017-05-10 17:38:42 +00:00
|
|
|
};
|
|
|
|
|
2018-04-22 03:32:42 +00:00
|
|
|
namespace detail
|
|
|
|
{
|
2019-12-05 20:46:41 +00:00
|
|
|
class GetSteps : public vtkm::worklet::WorkletMapField
|
2018-04-22 03:32:42 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT
|
2019-12-05 20:46:41 +00:00
|
|
|
GetSteps() {}
|
|
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
|
|
|
using ExecutionSignature = void(_1, _2);
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Particle& p, vtkm::Id& numSteps) const
|
|
|
|
{
|
|
|
|
numSteps = p.NumSteps;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ComputeNumPoints : public vtkm::worklet::WorkletMapField
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT
|
|
|
|
ComputeNumPoints() {}
|
|
|
|
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(_1, _2, _3);
|
2019-12-05 20:46:41 +00:00
|
|
|
|
|
|
|
// Offset is number of points in streamline.
|
|
|
|
// 1 (inital point) + number of steps taken (p.NumSteps - initalNumSteps)
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Particle& p,
|
|
|
|
const vtkm::Id& initialNumSteps,
|
|
|
|
vtkm::Id& diff) const
|
2018-04-22 03:32:42 +00:00
|
|
|
{
|
2019-12-05 20:46:41 +00:00
|
|
|
diff = 1 + p.NumSteps - initialNumSteps;
|
2018-04-22 03:32:42 +00:00
|
|
|
}
|
|
|
|
};
|
2018-07-11 15:47:32 +00:00
|
|
|
} // namespace detail
|
2017-05-10 17:38:42 +00:00
|
|
|
|
2019-10-10 13:46:29 +00:00
|
|
|
|
2020-07-21 01:15:46 +00:00
|
|
|
template <typename IntegratorType, typename ParticleType>
|
2017-07-08 19:54:44 +00:00
|
|
|
class StreamlineWorklet
|
2017-05-10 17:38:42 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-12-04 16:52:08 +00:00
|
|
|
template <typename PointStorage, typename PointStorage2>
|
2017-07-12 02:22:28 +00:00
|
|
|
void Run(const IntegratorType& it,
|
2020-07-21 01:15:46 +00:00
|
|
|
vtkm::cont::ArrayHandle<ParticleType, PointStorage>& particles,
|
2019-12-04 16:52:08 +00:00
|
|
|
vtkm::Id& MaxSteps,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec3f, PointStorage2>& positions,
|
|
|
|
vtkm::cont::CellSetExplicit<>& polyLines)
|
2019-10-10 13:46:29 +00:00
|
|
|
{
|
|
|
|
|
2018-07-11 15:47:32 +00:00
|
|
|
using ParticleWorkletDispatchType = typename vtkm::worklet::DispatcherMapField<
|
|
|
|
vtkm::worklet::particleadvection::ParticleAdvectWorklet>;
|
2020-07-21 01:15:46 +00:00
|
|
|
using StreamlineArrayType =
|
|
|
|
vtkm::worklet::particleadvection::StateRecordingParticles<ParticleType>;
|
2017-07-07 17:36:31 +00:00
|
|
|
|
2019-12-05 20:46:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> initialStepsTaken;
|
2017-07-07 17:36:31 +00:00
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
vtkm::Id numSeeds = static_cast<vtkm::Id>(particles.GetNumberOfValues());
|
2017-07-21 18:37:20 +00:00
|
|
|
vtkm::cont::ArrayHandleIndex idxArray(numSeeds);
|
2017-07-07 17:36:31 +00:00
|
|
|
|
2019-12-05 20:46:41 +00:00
|
|
|
vtkm::worklet::DispatcherMapField<detail::GetSteps> getStepDispatcher{ (detail::GetSteps{}) };
|
|
|
|
getStepDispatcher.Invoke(particles, initialStepsTaken);
|
|
|
|
|
2021-07-29 18:47:29 +00:00
|
|
|
// This method uses the same workklet as ParticleAdvectionWorklet::Run (and more). Yet for
|
|
|
|
// some reason ParticleAdvectionWorklet::Run needs this adjustment while this method does
|
|
|
|
// not.
|
2019-12-05 20:46:41 +00:00
|
|
|
#ifdef VTKM_CUDA
|
2021-07-29 18:47:29 +00:00
|
|
|
// // This worklet needs some extra space on CUDA.
|
|
|
|
// vtkm::cont::cuda::internal::ScopedCudaStackSize stack(16 * 1024);
|
|
|
|
// (void)stack;
|
2019-12-05 20:46:41 +00:00
|
|
|
#endif // VTKM_CUDA
|
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
//Run streamline worklet
|
2020-07-21 01:15:46 +00:00
|
|
|
StreamlineArrayType streamlines(particles, MaxSteps);
|
2019-12-04 16:52:08 +00:00
|
|
|
ParticleWorkletDispatchType particleWorkletDispatch;
|
|
|
|
vtkm::cont::ArrayHandleConstant<vtkm::Id> maxSteps(MaxSteps, numSeeds);
|
|
|
|
particleWorkletDispatch.Invoke(idxArray, it, streamlines, maxSteps);
|
2017-08-28 20:58:44 +00:00
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
//Get the positions
|
|
|
|
streamlines.GetCompactedHistory(positions);
|
2017-07-21 18:37:20 +00:00
|
|
|
|
2019-12-04 16:52:08 +00:00
|
|
|
//Create the cells
|
2019-12-05 20:46:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> numPoints;
|
|
|
|
vtkm::worklet::DispatcherMapField<detail::ComputeNumPoints> computeNumPointsDispatcher{ (
|
|
|
|
detail::ComputeNumPoints{}) };
|
|
|
|
computeNumPointsDispatcher.Invoke(particles, initialStepsTaken, numPoints);
|
2018-04-22 03:32:42 +00:00
|
|
|
|
2017-07-21 18:37:20 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> cellIndex;
|
2019-12-05 20:46:41 +00:00
|
|
|
vtkm::Id connectivityLen = vtkm::cont::Algorithm::ScanExclusive(numPoints, cellIndex);
|
2017-07-21 18:37:20 +00:00
|
|
|
vtkm::cont::ArrayHandleCounting<vtkm::Id> connCount(0, 1, connectivityLen);
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayCopy(connCount, connectivity);
|
2017-07-21 18:37:20 +00:00
|
|
|
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::UInt8> cellTypes;
|
2019-12-04 16:52:08 +00:00
|
|
|
auto polyLineShape =
|
|
|
|
vtkm::cont::make_ArrayHandleConstant<vtkm::UInt8>(vtkm::CELL_SHAPE_POLY_LINE, numSeeds);
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayCopy(polyLineShape, cellTypes);
|
2017-07-21 18:37:20 +00:00
|
|
|
|
2021-08-18 20:47:40 +00:00
|
|
|
auto offsets = vtkm::cont::ConvertNumComponentsToOffsets(numPoints);
|
2019-12-04 16:52:08 +00:00
|
|
|
polyLines.Fill(positions.GetNumberOfValues(), cellTypes, connectivity, offsets);
|
|
|
|
}
|
2017-04-18 20:49:03 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2018-07-11 15:47:32 +00:00
|
|
|
} // namespace vtkm::worklet::particleadvection
|
2017-04-18 20:49:03 +00:00
|
|
|
|
2017-07-08 19:54:44 +00:00
|
|
|
#endif // vtk_m_worklet_particleadvection_ParticleAdvectionWorklets_h
|