Add vtkm::source::Wavelet as a new source

The Wavelet source creates a dataset similar to VTK's vtkRTAnalyticSource.
This commit is contained in:
Robert Maynard 2019-09-13 10:07:41 -04:00
parent 257dc1f84e
commit 63f2438098
8 changed files with 311 additions and 19 deletions

@ -46,8 +46,8 @@
#include <vtkm/io/reader/VTKDataSetReader.h>
#include <vtkm/source/Wavelet.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WaveletGenerator.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <cctype> // for std::tolower
@ -1357,10 +1357,10 @@ int BenchmarkBody(int argc, char** argv, const vtkm::cont::InitializeResult& con
{
std::cout << "Generating " << waveletDim << "x" << waveletDim << "x" << waveletDim
<< " wavelet...\n";
vtkm::worklet::WaveletGenerator gen;
gen.SetExtent({ 0 }, { waveletDim });
vtkm::source::Wavelet source;
source.SetExtent({ 0 }, { waveletDim });
InputDataSet = gen.GenerateDataSet(config.Device);
InputDataSet = source.Execute();
}
if (tetra)

@ -42,7 +42,7 @@ set(benchmarks
)
foreach (benchmark ${benchmarks})
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_filter)
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter)
endforeach ()
if(TARGET vtkm_rendering)

@ -15,7 +15,7 @@
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/worklet/WaveletGenerator.h>
#include <vtkm/source/Wavelet.h>
namespace
{
@ -115,13 +115,11 @@ vtkm::cont::DataSet Make3DExplicitSimpleCube()
vtkm::cont::DataSet Make3DWavelet()
{
vtkm::worklet::WaveletGenerator wavelet;
wavelet.SetMinimumExtent({ -25 });
wavelet.SetMaximumExtent({ 25 });
vtkm::source::Wavelet wavelet({ -25 }, { 25 });
wavelet.SetFrequency({ 60, 30, 40 });
wavelet.SetMagnitude({ 5 });
vtkm::cont::DataSet result = wavelet.GenerateDataSet();
vtkm::cont::DataSet result = wavelet.Execute();
return result;
}

@ -11,11 +11,13 @@
set(headers
Source.h
Tangle.h
Wavelet.h
)
set(device_sources
Source.cxx
Tangle.cxx
Wavelet.cxx
)
vtkm_library(NAME vtkm_source

183
vtkm/source/Wavelet.cxx Normal file

@ -0,0 +1,183 @@
//============================================================================
// 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/Wavelet.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
inline 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.);
}
}
namespace vtkm
{
namespace source
{
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;
}
};
} // namespace wavelet
Wavelet::Wavelet(vtkm::Id3 minExtent, vtkm::Id3 maxExtent)
: Center{ minExtent - ((minExtent - maxExtent) / 2) }
, Spacing{ 1. }
, Frequency{ 60., 30., 40. }
, Magnitude{ 10., 18., 5. }
, MinimumExtent{ minExtent }
, MaximumExtent{ maxExtent }
, MaximumValue{ 255. }
, StandardDeviation{ 0.5 }
{
}
vtkm::cont::DataSet Wavelet::Execute() const
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
// Create points:
const vtkm::Id3 dims{ this->MaximumExtent - this->MinimumExtent + vtkm::Id3{ 1 } };
const vtkm::Vec3f origin{ this->MinimumExtent };
vtkm::cont::CoordinateSystem coords{ "coordinates", dims, origin, this->Spacing };
// And cells:
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(dims);
// Compile the dataset:
vtkm::cont::DataSet dataSet;
dataSet.AddCoordinateSystem(coords);
dataSet.SetCellSet(cellSet);
// Scalars, too
vtkm::cont::Field field = this->GeneratePointField("scalars");
dataSet.AddField(field);
return dataSet;
}
vtkm::cont::Field Wavelet::GeneratePointField(const std::string& name) const
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
const vtkm::Id3 dims{ this->MaximumExtent - this->MinimumExtent + vtkm::Id3{ 1 } };
vtkm::Vec3f minPt = vtkm::Vec3f(this->MinimumExtent) * this->Spacing;
vtkm::FloatDefault temp2 = 1.f / (2.f * this->StandardDeviation * this->StandardDeviation);
vtkm::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(this->Invoke.GetDevice(),
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);
}
} // namespace source
} // namespace vtkm

111
vtkm/source/Wavelet.h Normal file

@ -0,0 +1,111 @@
//============================================================================
// 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_source_Wavelet_h
#define vtk_m_source_Wavelet_h
#include <vtkm/source/Source.h>
namespace vtkm
{
namespace source
{
/**
* @brief The Wavelet source 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 Execute method creates a complete structured dataset that have a
* point field names 'scalars'
*
* 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 VTKM_SOURCE_EXPORT Wavelet final : public vtkm::source::Source
{
public:
VTKM_CONT
Wavelet(vtkm::Id3 minExtent = { -10 }, vtkm::Id3 maxExtent = { 10 });
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::DataSet Execute() const;
private:
vtkm::cont::Field GeneratePointField(const std::string& name) const;
vtkm::Vec3f Center;
vtkm::Vec3f Spacing;
vtkm::Vec3f Frequency;
vtkm::Vec3f Magnitude;
vtkm::Id3 MinimumExtent;
vtkm::Id3 MaximumExtent;
vtkm::FloatDefault MaximumValue;
vtkm::FloatDefault StandardDeviation;
};
} //namespace source
} //namespace vtkm
#endif //vtk_m_source_Wavelet_h

@ -13,7 +13,7 @@
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/testing/Testing.h>
void WaveletGeneratorTest()
void WaveletSourceTest()
{
vtkm::cont::Timer timer;
timer.Start();
@ -27,7 +27,7 @@ void WaveletGeneratorTest()
std::cout << "Default wavelet took " << time << "s.\n";
{
auto coords = ds.GetCoordinateSystem("coords");
auto coords = ds.GetCoordinateSystem("coordinates");
auto data = coords.GetData();
VTKM_TEST_ASSERT(test_equal(data.GetNumberOfValues(), 9261), "Incorrect number of points.");
}
@ -63,7 +63,7 @@ void WaveletGeneratorTest()
}
}
int UnitTestWaveletGenerator(int argc, char* argv[])
int UnitTestWaveletSource(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(WaveletGeneratorTest, argc, argv);
return vtkm::cont::testing::Testing::Run(WaveletSourceTest, argc, argv);
}

@ -37,7 +37,7 @@
#include <vtkm/filter/PolicyBase.h>
#include <vtkm/filter/SurfaceNormals.h>
#include <vtkm/worklet/WaveletGenerator.h>
#include <vtkm/source/Wavelet.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
@ -59,12 +59,10 @@ struct TestPolicy : public vtkm::filter::PolicyBase<TestPolicy>
VTKM_CONT
vtkm::cont::DataSet CreateDataSet(bool pointNormals, bool cellNormals)
{
vtkm::worklet::WaveletGenerator wavelet;
wavelet.SetMinimumExtent({ -25 });
wavelet.SetMaximumExtent({ 25 });
vtkm::source::Wavelet wavelet({ -25 }, { 25 });
wavelet.SetFrequency({ 20, 15, 25 });
wavelet.SetMagnitude({ 5 });
auto dataSet = wavelet.GenerateDataSet();
auto dataSet = wavelet.Execute();
// Cut a contour
vtkm::filter::Contour contour;