Sources have a more consistent API and internal style.

`vtkm::source::Source` now uses virtual inheritance for
the `Execute` method. This will allow us to enforce that
all vtkm::source have a consistent calling convention.

To make the code inside filters and sources more similar the
base `vtkm::source::Source` class has a `vtkm::cont::Invoker`
as a member variable. This will allow sources to use the
`this->Invoke()` pattern that filters use to launch worklets.
This commit is contained in:
Robert Maynard 2019-09-13 08:12:58 -04:00
parent 2d455bbef8
commit 257dc1f84e
9 changed files with 63 additions and 300 deletions

@ -14,6 +14,7 @@ set(headers
)
set(device_sources
Source.cxx
Tangle.cxx
)
@ -22,4 +23,7 @@ vtkm_library(NAME vtkm_source
HEADERS ${headers}
)
target_link_libraries(vtkm_source PUBLIC vtkm_worklet)
target_link_libraries(vtkm_source PUBLIC vtkm_cont)
#-----------------------------------------------------------------------------
add_subdirectory(testing)

24
vtkm/source/Source.cxx Normal file

@ -0,0 +1,24 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/source/Source.h>
namespace vtkm
{
namespace source
{
//Fix the vtable for Source to be in the vtkm_source library
Source::Source() = default;
Source::~Source() = default;
} // namespace source
} // namespace vtkm

@ -12,21 +12,26 @@
#define vtk_m_source_Source_h
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/source/vtkm_source_export.h>
namespace vtkm
{
namespace source
{
class Source
class VTKM_SOURCE_EXPORT Source
{
public:
VTKM_CONT
Source() {}
Source();
VTKM_CONT
~Source() {}
virtual ~Source();
virtual vtkm::cont::DataSet Execute() const = 0;
protected:
vtkm::cont::Invoker Invoke;
};
} // namespace source

@ -8,8 +8,8 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/source/Tangle.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
@ -71,7 +71,6 @@ public:
};
} // namespace tangle
VTKM_SOURCE_EXPORT
vtkm::cont::DataSet Tangle::Execute() const
{
vtkm::cont::DataSet dataSet;
@ -83,9 +82,8 @@ vtkm::cont::DataSet Tangle::Execute() const
vtkm::cont::ArrayHandle<vtkm::Float32> pointFieldArray;
vtkm::cont::ArrayHandleIndex vertexCountImplicitArray(vdims[0] * vdims[1] * vdims[2]);
vtkm::worklet::DispatcherMapField<tangle::TangleField> tangleFieldDispatcher(
tangle::TangleField(vdims, mins, maxs));
tangleFieldDispatcher.Invoke(vertexCountImplicitArray, pointFieldArray);
this->Invoke(tangle::TangleField{ vdims, mins, maxs }, vertexCountImplicitArray, pointFieldArray);
vtkm::Id numCells = Dims[0] * Dims[1] * Dims[2];
vtkm::cont::ArrayHandle<vtkm::FloatDefault> cellFieldArray;

@ -0,0 +1,19 @@
##============================================================================
## 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.
##============================================================================
set(unit_tests
UnitTestWaveletSource.cxx
)
vtkm_unit_tests(
SOURCES ${unit_tests}
LIBRARIES vtkm_source
ALL_BACKENDS
)

@ -8,7 +8,7 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/worklet/WaveletGenerator.h>
#include <vtkm/source/Wavelet.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/testing/Testing.h>
@ -18,8 +18,8 @@ void WaveletGeneratorTest()
vtkm::cont::Timer timer;
timer.Start();
vtkm::worklet::WaveletGenerator gen;
vtkm::cont::DataSet ds = gen.GenerateDataSet();
vtkm::source::Wavelet source;
vtkm::cont::DataSet ds = source.Execute();
double time = timer.GetElapsedTime();

@ -82,7 +82,6 @@ set(headers
WarpScalar.h
WarpVector.h
WaveletCompressor.h
WaveletGenerator.h
WorkletMapField.h
WorkletMapTopology.h
WorkletPointNeighborhood.h

@ -1,285 +0,0 @@
//============================================================================
// 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_worklet_waveletgenerator_h
#define vtk_m_worklet_waveletgenerator_h
#include <vtkm/Types.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/exec/FunctorBase.h>
#include <string>
#include <utility>
namespace vtkm
{
namespace worklet
{
namespace wavelet
{
template <typename Device>
struct Worker : public vtkm::exec::FunctorBase
{
using OutputHandleType = vtkm::cont::ArrayHandle<vtkm::FloatDefault>;
using OutputPortalType = decltype(std::declval<OutputHandleType>().PrepareForOutput(0, Device()));
using Vec3F = vtkm::Vec3f;
Vec3F Center;
Vec3F Spacing;
Vec3F Frequency;
Vec3F Magnitude;
Vec3F MinimumPoint;
Vec3F Scale;
vtkm::Id3 Offset;
vtkm::Id3 Dims;
vtkm::FloatDefault MaximumValue;
vtkm::FloatDefault Temp2;
OutputPortalType Portal;
VTKM_CONT
Worker(OutputHandleType& output,
const Vec3F& center,
const Vec3F& spacing,
const Vec3F& frequency,
const Vec3F& magnitude,
const Vec3F& minimumPoint,
const Vec3F& scale,
const vtkm::Id3& offset,
const vtkm::Id3& dims,
vtkm::FloatDefault maximumValue,
vtkm::FloatDefault temp2)
: Center(center)
, Spacing(spacing)
, Frequency(frequency)
, Magnitude(magnitude)
, MinimumPoint(minimumPoint)
, Scale(scale)
, Offset(offset)
, Dims(dims)
, MaximumValue(maximumValue)
, Temp2(temp2)
, Portal(output.PrepareForOutput((dims[0] * dims[1] * dims[2]), Device{}))
{
}
VTKM_EXEC
void operator()(const vtkm::Id3& ijk) const
{
// map ijk to the point location, accounting for spacing:
const Vec3F loc = Vec3F(ijk + this->Offset) * this->Spacing;
// Compute the distance from the center of the gaussian:
const Vec3F scaledLoc = (this->Center - loc) * this->Scale;
vtkm::FloatDefault gaussSum = vtkm::Dot(scaledLoc, scaledLoc);
const Vec3F periodicContribs{
this->Magnitude[0] * vtkm::Sin(this->Frequency[0] * scaledLoc[0]),
this->Magnitude[1] * vtkm::Sin(this->Frequency[1] * scaledLoc[1]),
this->Magnitude[2] * vtkm::Cos(this->Frequency[2] * scaledLoc[2]),
};
// The vtkRTAnalyticSource documentation says the periodic contributions
// should be multiplied in, but the implementation adds them. We'll do as
// they do, not as they say.
const vtkm::FloatDefault scalar = this->MaximumValue * vtkm::Exp(-gaussSum * this->Temp2) +
periodicContribs[0] + periodicContribs[1] + periodicContribs[2];
// Compute output location
// (see ConnectivityStructuredInternals<3>::LogicalToFlatPointIndex)
const vtkm::Id scalarIdx = ijk[0] + this->Dims[0] * (ijk[1] + this->Dims[1] * ijk[2]);
this->Portal.Set(scalarIdx, scalar);
}
};
struct runWorker
{
template <typename Device, typename... Args>
inline bool operator()(Device, const vtkm::Id3 dims, Args... args) const
{
using Algo = vtkm::cont::DeviceAdapterAlgorithm<Device>;
Worker<Device> worker{ args... };
Algo::Schedule(worker, dims);
return true;
}
};
}
/**
* @brief The WaveletGenerator class creates a dataset similar to VTK's
* vtkRTAnalyticSource.
*
* This class generates a predictable structured dataset with a smooth yet
* interesting set of scalars, which is useful for testing and benchmarking.
*
* The GenerateDataSet method can be used to create a complete structured
* dataset, while GenerateField will generate the scalar point field only.
*
* The scalars are computed as:
*
* ```
* MaxVal * Gauss + MagX * sin(FrqX*x) + MagY * sin(FrqY*y) + MagZ * cos(FrqZ*z)
* ```
*
* The dataset properties are determined by:
* - `Minimum/MaximumExtent`: The logical point extents of the dataset.
* - `Spacing`: The distance between points of the dataset.
* - `Center`: The center of the dataset.
*
* The scalar functions is control via:
* - `Center`: The center of a Gaussian contribution to the scalars.
* - `StandardDeviation`: The unscaled width of a Gaussian contribution.
* - `MaximumValue`: Upper limit of the scalar range.
* - `Frequency`: The Frq[XYZ] parameters of the periodic contributions.
* - `Magnitude`: The Mag[XYZ] parameters of the periodic contributions.
*
* By default, the following parameters are used:
* - `Extents`: { -10, -10, -10 } `-->` { 10, 10, 10 }
* - `Spacing`: { 1, 1, 1 }
* - `Center`: { 0, 0, 0 }
* - `StandardDeviation`: 0.5
* - `MaximumValue`: 255
* - `Frequency`: { 60, 30, 40 }
* - `Magnitude`: { 10, 18, 5 }
*/
class WaveletGenerator
{
using Vec3F = vtkm::Vec3f;
Vec3F Center;
Vec3F Spacing;
Vec3F Frequency;
Vec3F Magnitude;
vtkm::Id3 MinimumExtent;
vtkm::Id3 MaximumExtent;
FloatDefault MaximumValue;
FloatDefault StandardDeviation;
public:
VTKM_CONT
WaveletGenerator()
: Center{ 0. }
, Spacing{ 1. }
, Frequency{ 60., 30., 40. }
, Magnitude{ 10., 18., 5. }
, MinimumExtent{ -10 }
, MaximumExtent{ 10 }
, MaximumValue{ 255. }
, StandardDeviation{ 0.5 }
{
}
VTKM_CONT void SetCenter(const vtkm::Vec<FloatDefault, 3>& center) { this->Center = center; }
VTKM_CONT void SetSpacing(const vtkm::Vec<FloatDefault, 3>& spacing) { this->Spacing = spacing; }
VTKM_CONT void SetFrequency(const vtkm::Vec<FloatDefault, 3>& frequency)
{
this->Frequency = frequency;
}
VTKM_CONT void SetMagnitude(const vtkm::Vec<FloatDefault, 3>& magnitude)
{
this->Magnitude = magnitude;
}
VTKM_CONT void SetMinimumExtent(const vtkm::Id3& minExtent) { this->MinimumExtent = minExtent; }
VTKM_CONT void SetMaximumExtent(const vtkm::Id3& maxExtent) { this->MaximumExtent = maxExtent; }
VTKM_CONT void SetExtent(const vtkm::Id3& minExtent, const vtkm::Id3& maxExtent)
{
this->MinimumExtent = minExtent;
this->MaximumExtent = maxExtent;
}
VTKM_CONT void SetMaximumValue(const vtkm::FloatDefault& maxVal) { this->MaximumValue = maxVal; }
VTKM_CONT void SetStandardDeviation(const vtkm::FloatDefault& stdev)
{
this->StandardDeviation = stdev;
}
VTKM_CONT vtkm::cont::DataSet GenerateDataSet(
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()) const
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
// Create points:
const vtkm::Id3 dims{ this->MaximumExtent - this->MinimumExtent + vtkm::Id3{ 1 } };
const Vec3F origin{ this->MinimumExtent };
vtkm::cont::CoordinateSystem coords{ "coords", dims, origin, this->Spacing };
// And cells:
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(dims);
// Scalars, too
vtkm::cont::Field field = this->GenerateField("scalars", device);
// Compile the dataset:
vtkm::cont::DataSet dataSet;
dataSet.AddCoordinateSystem(coords);
dataSet.SetCellSet(cellSet);
dataSet.AddField(field);
return dataSet;
}
VTKM_CONT vtkm::cont::Field GenerateField(
const std::string& name,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny()) const
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
const vtkm::Id3 dims{ this->MaximumExtent - this->MinimumExtent + vtkm::Id3{ 1 } };
Vec3F minPt = Vec3F(this->MinimumExtent) * this->Spacing;
vtkm::FloatDefault temp2 = 1.f / (2.f * this->StandardDeviation * this->StandardDeviation);
Vec3F scale{ ComputeScaleFactor(this->MinimumExtent[0], this->MaximumExtent[0]),
ComputeScaleFactor(this->MinimumExtent[1], this->MaximumExtent[1]),
ComputeScaleFactor(this->MinimumExtent[2], this->MaximumExtent[2]) };
vtkm::cont::ArrayHandle<vtkm::FloatDefault> output;
vtkm::cont::TryExecuteOnDevice(device,
wavelet::runWorker{},
dims,
output,
this->Center,
this->Spacing,
this->Frequency,
this->Magnitude,
minPt,
scale,
this->MinimumExtent,
dims,
this->MaximumValue,
temp2);
return vtkm::cont::make_FieldPoint(name, output);
}
private:
static vtkm::FloatDefault ComputeScaleFactor(vtkm::Id min, vtkm::Id max)
{
return (min < max) ? (1.f / static_cast<vtkm::FloatDefault>(max - min))
: static_cast<vtkm::FloatDefault>(1.);
}
};
}
} // end namespace vtkm::worklet
#endif // vtk_m_worklet_waveletgenerator_h

@ -82,7 +82,6 @@ set(unit_tests
UnitTestWarpScalar.cxx
UnitTestWarpVector.cxx
UnitTestWaveletCompressor.cxx
UnitTestWaveletGenerator.cxx
UnitTestZFPCompressor.cxx
)