mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-19 18:45:43 +00:00
Merge branch 'master' of https://gitlab.kitware.com/vtk/vtk-m
This commit is contained in:
commit
5b898cd4f7
@ -56,7 +56,7 @@ build:ubuntu1604_gcc5_2:
|
|||||||
CC: "gcc-5"
|
CC: "gcc-5"
|
||||||
CXX: "g++-5"
|
CXX: "g++-5"
|
||||||
CMAKE_BUILD_TYPE: Release
|
CMAKE_BUILD_TYPE: Release
|
||||||
VTKM_SETTINGS: "openmp+cuda+pascal+examples+static+use_virtuals"
|
VTKM_SETTINGS: "openmp+cuda+pascal+examples+static"
|
||||||
|
|
||||||
test:ubuntu1804_test_ubuntu1604_gcc5_2:
|
test:ubuntu1804_test_ubuntu1604_gcc5_2:
|
||||||
tags:
|
tags:
|
||||||
|
958
benchmarking/BenchmarkInSitu.cxx
Normal file
958
benchmarking/BenchmarkInSitu.cxx
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
//==========================================================================
|
||||||
|
// 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 "Benchmarker.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <vtkm/ImplicitFunction.h>
|
||||||
|
|
||||||
|
#include <vtkm/cont/BoundsCompute.h>
|
||||||
|
#include <vtkm/cont/DataSet.h>
|
||||||
|
#include <vtkm/cont/FieldRangeCompute.h>
|
||||||
|
#include <vtkm/cont/Initialize.h>
|
||||||
|
#include <vtkm/cont/Logging.h>
|
||||||
|
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||||
|
#include <vtkm/cont/Timer.h>
|
||||||
|
|
||||||
|
#include <vtkm/cont/internal/OptionParser.h>
|
||||||
|
|
||||||
|
#include <vtkm/filter/Contour.h>
|
||||||
|
#include <vtkm/filter/Gradient.h>
|
||||||
|
#include <vtkm/filter/Slice.h>
|
||||||
|
#include <vtkm/filter/Streamline.h>
|
||||||
|
#include <vtkm/filter/Tetrahedralize.h>
|
||||||
|
#include <vtkm/filter/Tube.h>
|
||||||
|
|
||||||
|
#include <vtkm/rendering/Actor.h>
|
||||||
|
#include <vtkm/rendering/CanvasRayTracer.h>
|
||||||
|
#include <vtkm/rendering/MapperRayTracer.h>
|
||||||
|
#include <vtkm/rendering/MapperVolume.h>
|
||||||
|
#include <vtkm/rendering/MapperWireframer.h>
|
||||||
|
#include <vtkm/rendering/Scene.h>
|
||||||
|
#include <vtkm/rendering/View3D.h>
|
||||||
|
|
||||||
|
#include <vtkm/source/PerlinNoise.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const uint32_t DEFAULT_NUM_CYCLES = 20;
|
||||||
|
const vtkm::Id DEFAULT_DATASET_DIM = 128;
|
||||||
|
const vtkm::Id DEFAULT_IMAGE_SIZE = 1024;
|
||||||
|
|
||||||
|
// Hold configuration state (e.g. active device):
|
||||||
|
vtkm::cont::InitializeResult Config;
|
||||||
|
// Input dataset dimensions:
|
||||||
|
vtkm::Id DataSetDim;
|
||||||
|
// Image size:
|
||||||
|
vtkm::Id ImageSize;
|
||||||
|
// The input datasets we'll use on the filters:
|
||||||
|
vtkm::cont::DataSet InputDataSet;
|
||||||
|
vtkm::cont::PartitionedDataSet PartitionedInputDataSet;
|
||||||
|
// The point scalars to use:
|
||||||
|
std::string PointScalarsName;
|
||||||
|
// The point vectors to use:
|
||||||
|
std::string PointVectorsName;
|
||||||
|
|
||||||
|
enum class RenderingMode
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Mesh = 1,
|
||||||
|
RayTrace = 2,
|
||||||
|
Volume = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<vtkm::cont::DataSet> ExtractDataSets(const vtkm::cont::PartitionedDataSet& partitions)
|
||||||
|
{
|
||||||
|
return partitions.GetPartitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mirrors ExtractDataSet(ParitionedDataSet), to keep code simple at use sites
|
||||||
|
std::vector<vtkm::cont::DataSet> ExtractDataSets(vtkm::cont::DataSet& dataSet)
|
||||||
|
{
|
||||||
|
return std::vector<vtkm::cont::DataSet>{ dataSet };
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildInputDataSet(uint32_t cycle, bool isStructured, bool isMultiBlock, vtkm::Id dim)
|
||||||
|
{
|
||||||
|
vtkm::cont::PartitionedDataSet partitionedInputDataSet;
|
||||||
|
vtkm::cont::DataSet inputDataSet;
|
||||||
|
|
||||||
|
PointScalarsName = "perlinnoise";
|
||||||
|
PointVectorsName = "perlinnoisegrad";
|
||||||
|
|
||||||
|
// Generate uniform dataset(s)
|
||||||
|
const vtkm::Id3 dims{ dim, dim, dim };
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
for (auto j = 0; j < 2; ++j)
|
||||||
|
{
|
||||||
|
for (auto k = 0; k < 2; ++k)
|
||||||
|
{
|
||||||
|
const vtkm::Vec3f origin{ static_cast<vtkm::FloatDefault>(i),
|
||||||
|
static_cast<vtkm::FloatDefault>(j),
|
||||||
|
static_cast<vtkm::FloatDefault>(k) };
|
||||||
|
const vtkm::source::PerlinNoise noise{ dims,
|
||||||
|
origin,
|
||||||
|
static_cast<vtkm::IdComponent>(cycle) };
|
||||||
|
const auto dataset = noise.Execute();
|
||||||
|
partitionedInputDataSet.AppendPartition(dataset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const vtkm::source::PerlinNoise noise{ dims, static_cast<vtkm::IdComponent>(cycle) };
|
||||||
|
inputDataSet = noise.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Perln Noise Gradient point vector field
|
||||||
|
vtkm::filter::Gradient gradientFilter;
|
||||||
|
gradientFilter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::POINTS);
|
||||||
|
gradientFilter.SetComputePointGradient(true);
|
||||||
|
gradientFilter.SetOutputFieldName(PointVectorsName);
|
||||||
|
gradientFilter.SetFieldsToPass(
|
||||||
|
vtkm::filter::FieldSelection(vtkm::filter::FieldSelection::MODE_ALL));
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
partitionedInputDataSet = gradientFilter.Execute(partitionedInputDataSet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputDataSet = gradientFilter.Execute(inputDataSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Tetrahedralize filter to convert uniform dataset(s) into unstructured ones
|
||||||
|
if (!isStructured)
|
||||||
|
{
|
||||||
|
vtkm::filter::Tetrahedralize destructizer;
|
||||||
|
destructizer.SetFieldsToPass(
|
||||||
|
vtkm::filter::FieldSelection(vtkm::filter::FieldSelection::MODE_ALL));
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
partitionedInputDataSet = destructizer.Execute(partitionedInputDataSet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputDataSet = destructizer.Execute(inputDataSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release execution resources to simulate in-situ workload, where the data is
|
||||||
|
// not present in the execution environment
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets =
|
||||||
|
isMultiBlock ? ExtractDataSets(partitionedInputDataSet) : ExtractDataSets(inputDataSet);
|
||||||
|
for (auto& dataSet : dataSets)
|
||||||
|
{
|
||||||
|
dataSet.GetCellSet().ReleaseResourcesExecution();
|
||||||
|
dataSet.GetCoordinateSystem().ReleaseResourcesExecution();
|
||||||
|
dataSet.GetField(PointScalarsName).ReleaseResourcesExecution();
|
||||||
|
dataSet.GetField(PointVectorsName).ReleaseResourcesExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
PartitionedInputDataSet = partitionedInputDataSet;
|
||||||
|
InputDataSet = inputDataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::rendering::Canvas* RenderDataSets(const std::vector<vtkm::cont::DataSet>& dataSets,
|
||||||
|
RenderingMode mode,
|
||||||
|
std::string fieldName)
|
||||||
|
{
|
||||||
|
vtkm::rendering::Scene scene;
|
||||||
|
vtkm::cont::ColorTable colorTable("inferno");
|
||||||
|
if (mode == RenderingMode::Volume)
|
||||||
|
{
|
||||||
|
colorTable.AddPointAlpha(0.0f, 0.03f);
|
||||||
|
colorTable.AddPointAlpha(1.0f, 0.01f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& dataSet : dataSets)
|
||||||
|
{
|
||||||
|
scene.AddActor(vtkm::rendering::Actor(dataSet.GetCellSet(),
|
||||||
|
dataSet.GetCoordinateSystem(),
|
||||||
|
dataSet.GetField(fieldName),
|
||||||
|
colorTable));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bounds = std::accumulate(dataSets.begin(),
|
||||||
|
dataSets.end(),
|
||||||
|
vtkm::Bounds(),
|
||||||
|
[=](const vtkm::Bounds& val, const vtkm::cont::DataSet& partition) {
|
||||||
|
return val + vtkm::cont::BoundsCompute(partition);
|
||||||
|
});
|
||||||
|
vtkm::Vec3f_64 totalExtent(bounds.X.Length(), bounds.Y.Length(), bounds.Z.Length());
|
||||||
|
vtkm::Float64 mag = vtkm::Magnitude(totalExtent);
|
||||||
|
vtkm::Normalize(totalExtent);
|
||||||
|
|
||||||
|
// setup a camera and point it to towards the center of the input data
|
||||||
|
vtkm::rendering::Camera camera;
|
||||||
|
camera.SetFieldOfView(60.f);
|
||||||
|
camera.ResetToBounds(bounds);
|
||||||
|
camera.SetLookAt(totalExtent * (mag * .5f));
|
||||||
|
camera.SetViewUp(vtkm::make_Vec(0.f, 1.f, 0.f));
|
||||||
|
camera.SetPosition(totalExtent * (mag * 1.5f));
|
||||||
|
|
||||||
|
vtkm::rendering::CanvasRayTracer canvas(ImageSize, ImageSize);
|
||||||
|
|
||||||
|
auto mapper = [=]() -> std::unique_ptr<vtkm::rendering::Mapper> {
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RenderingMode::Mesh:
|
||||||
|
{
|
||||||
|
return std::unique_ptr<vtkm::rendering::Mapper>(new vtkm::rendering::MapperWireframer());
|
||||||
|
}
|
||||||
|
case RenderingMode::RayTrace:
|
||||||
|
{
|
||||||
|
return std::unique_ptr<vtkm::rendering::Mapper>(new vtkm::rendering::MapperRayTracer());
|
||||||
|
}
|
||||||
|
case RenderingMode::Volume:
|
||||||
|
{
|
||||||
|
return std::unique_ptr<vtkm::rendering::Mapper>(new vtkm::rendering::MapperVolume());
|
||||||
|
}
|
||||||
|
case RenderingMode::None:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return std::unique_ptr<vtkm::rendering::Mapper>(new vtkm::rendering::MapperRayTracer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
vtkm::rendering::View3D view(scene,
|
||||||
|
*mapper,
|
||||||
|
canvas,
|
||||||
|
camera,
|
||||||
|
vtkm::rendering::Color(0.8f, 0.8f, 0.6f),
|
||||||
|
vtkm::rendering::Color(0.2f, 0.4f, 0.2f));
|
||||||
|
view.Paint();
|
||||||
|
|
||||||
|
return view.GetCanvas().NewCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteToDisk(const vtkm::rendering::Canvas& canvas,
|
||||||
|
RenderingMode mode,
|
||||||
|
std::string bench,
|
||||||
|
bool isStructured,
|
||||||
|
bool isMultiBlock,
|
||||||
|
uint32_t cycle)
|
||||||
|
{
|
||||||
|
std::ostringstream nameBuilder;
|
||||||
|
nameBuilder << "insitu_" << bench << "_"
|
||||||
|
<< "cycle_" << cycle << "_" << (isStructured ? "structured_" : "unstructured_")
|
||||||
|
<< (isMultiBlock ? "multi_" : "single_")
|
||||||
|
<< (mode == RenderingMode::Mesh ? "mesh"
|
||||||
|
: (mode == RenderingMode::Volume ? "volume" : "ray"))
|
||||||
|
<< ".png";
|
||||||
|
canvas.SaveAs(nameBuilder.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename DataSetType>
|
||||||
|
DataSetType RunContourHelper(vtkm::filter::Contour& filter,
|
||||||
|
vtkm::Id numIsoVals,
|
||||||
|
const DataSetType& input)
|
||||||
|
{
|
||||||
|
// Set up some equally spaced contours, with the min/max slightly inside the
|
||||||
|
// scalar range:
|
||||||
|
const vtkm::Range scalarRange =
|
||||||
|
vtkm::cont::FieldRangeCompute(input, PointScalarsName).ReadPortal().Get(0);
|
||||||
|
const auto step = scalarRange.Length() / static_cast<vtkm::Float64>(numIsoVals + 1);
|
||||||
|
const auto minIsoVal = scalarRange.Min + (step * 0.5f);
|
||||||
|
filter.SetNumberOfIsoValues(numIsoVals);
|
||||||
|
for (vtkm::Id i = 0; i < numIsoVals; ++i)
|
||||||
|
{
|
||||||
|
filter.SetIsoValue(i, minIsoVal + (step * static_cast<vtkm::Float64>(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter.Execute(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchContour(::benchmark::State& state)
|
||||||
|
{
|
||||||
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||||
|
|
||||||
|
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
|
||||||
|
const vtkm::Id numIsoVals = static_cast<vtkm::Id>(state.range(1));
|
||||||
|
const bool isStructured = static_cast<bool>(state.range(2));
|
||||||
|
const bool isMultiBlock = static_cast<bool>(state.range(3));
|
||||||
|
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(4));
|
||||||
|
|
||||||
|
vtkm::cont::Timer inputGenTimer{ device };
|
||||||
|
inputGenTimer.Start();
|
||||||
|
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
|
||||||
|
inputGenTimer.Stop();
|
||||||
|
|
||||||
|
vtkm::filter::Contour filter;
|
||||||
|
filter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::POINTS);
|
||||||
|
filter.SetMergeDuplicatePoints(true);
|
||||||
|
filter.SetGenerateNormals(true);
|
||||||
|
filter.SetComputeFastNormalsForStructured(true);
|
||||||
|
filter.SetComputeFastNormalsForUnstructured(true);
|
||||||
|
|
||||||
|
vtkm::cont::Timer totalTimer{ device };
|
||||||
|
vtkm::cont::Timer filterTimer{ device };
|
||||||
|
vtkm::cont::Timer renderTimer{ device };
|
||||||
|
vtkm::cont::Timer writeTimer{ device };
|
||||||
|
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
(void)_;
|
||||||
|
totalTimer.Start();
|
||||||
|
filterTimer.Start();
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets;
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
auto input = PartitionedInputDataSet;
|
||||||
|
auto result = RunContourHelper(filter, numIsoVals, input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto input = InputDataSet;
|
||||||
|
auto result = RunContourHelper(filter, numIsoVals, input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
filterTimer.Stop();
|
||||||
|
|
||||||
|
renderTimer.Start();
|
||||||
|
auto canvas = RenderDataSets(dataSets, renderAlgo, PointScalarsName);
|
||||||
|
renderTimer.Stop();
|
||||||
|
|
||||||
|
writeTimer.Start();
|
||||||
|
WriteToDisk(*canvas, renderAlgo, "contour", isStructured, isMultiBlock, cycle);
|
||||||
|
writeTimer.Stop();
|
||||||
|
|
||||||
|
totalTimer.Stop();
|
||||||
|
|
||||||
|
state.SetIterationTime(totalTimer.GetElapsedTime());
|
||||||
|
state.counters.insert(
|
||||||
|
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "FilterTime", static_cast<uint32_t>(filterTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "RenderTime", static_cast<uint32_t>(renderTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "WriteTime", static_cast<uint32_t>(writeTimer.GetElapsedTime() * 1000) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchContourGenerator(::benchmark::internal::Benchmark* bm)
|
||||||
|
{
|
||||||
|
bm->ArgNames({ "Cycle", "NIsos", "IsStructured", "IsMultiBlock", "RenderingMode" });
|
||||||
|
|
||||||
|
std::vector<uint32_t> isStructureds{ false, true };
|
||||||
|
std::vector<uint32_t> isMultiBlocks{ false, true };
|
||||||
|
std::vector<RenderingMode> renderingModes{ RenderingMode::RayTrace };
|
||||||
|
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
|
||||||
|
{
|
||||||
|
for (auto& isStructured : isStructureds)
|
||||||
|
{
|
||||||
|
for (auto& isMultiBlock : isMultiBlocks)
|
||||||
|
{
|
||||||
|
for (auto& mode : renderingModes)
|
||||||
|
{
|
||||||
|
bm->Args({ cycle, 10, isStructured, isMultiBlock, static_cast<int>(mode) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_BENCHMARK_APPLY(BenchContour, BenchContourGenerator);
|
||||||
|
|
||||||
|
void MakeRandomSeeds(vtkm::Id seedCount,
|
||||||
|
vtkm::Bounds& bounds,
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::Particle>& seeds)
|
||||||
|
{
|
||||||
|
std::default_random_engine generator(static_cast<vtkm::UInt32>(255));
|
||||||
|
vtkm::FloatDefault zero(0), one(1);
|
||||||
|
std::uniform_real_distribution<vtkm::FloatDefault> distribution(zero, one);
|
||||||
|
std::vector<vtkm::Particle> points;
|
||||||
|
points.resize(0);
|
||||||
|
for (vtkm::Id i = 0; i < seedCount; i++)
|
||||||
|
{
|
||||||
|
vtkm::FloatDefault rx = distribution(generator);
|
||||||
|
vtkm::FloatDefault ry = distribution(generator);
|
||||||
|
vtkm::FloatDefault rz = distribution(generator);
|
||||||
|
vtkm::Vec3f p;
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::Particle> tmp =
|
||||||
|
vtkm::cont::make_ArrayHandle(points, vtkm::CopyFlag::Off);
|
||||||
|
vtkm::cont::ArrayCopy(tmp, seeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::Id GetNumberOfPoints(const vtkm::cont::DataSet& input)
|
||||||
|
{
|
||||||
|
return input.GetCoordinateSystem().GetNumberOfPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::Id GetNumberOfPoints(const vtkm::cont::PartitionedDataSet& input)
|
||||||
|
{
|
||||||
|
return input.GetPartition(0).GetCoordinateSystem().GetNumberOfPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddField(vtkm::cont::DataSet& input,
|
||||||
|
std::string fieldName,
|
||||||
|
std::vector<vtkm::FloatDefault>& field)
|
||||||
|
{
|
||||||
|
input.AddPointField(fieldName, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddField(vtkm::cont::PartitionedDataSet& input,
|
||||||
|
std::string fieldName,
|
||||||
|
std::vector<vtkm::FloatDefault>& field)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < input.GetNumberOfPartitions(); ++i)
|
||||||
|
{
|
||||||
|
auto partition = input.GetPartition(i);
|
||||||
|
AddField(partition, fieldName, field);
|
||||||
|
input.ReplacePartition(i, partition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DataSetType>
|
||||||
|
DataSetType RunStreamlinesHelper(vtkm::filter::Streamline& filter, const DataSetType& input)
|
||||||
|
{
|
||||||
|
auto dataSetBounds = vtkm::cont::BoundsCompute(input);
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::Particle> seedArray;
|
||||||
|
MakeRandomSeeds(100, dataSetBounds, seedArray);
|
||||||
|
filter.SetSeeds(seedArray);
|
||||||
|
|
||||||
|
auto result = filter.Execute(input);
|
||||||
|
auto numPoints = GetNumberOfPoints(result);
|
||||||
|
std::vector<vtkm::FloatDefault> colorMap(
|
||||||
|
static_cast<std::vector<vtkm::FloatDefault>::size_type>(numPoints));
|
||||||
|
for (std::vector<vtkm::FloatDefault>::size_type i = 0; i < colorMap.size(); i++)
|
||||||
|
{
|
||||||
|
colorMap[i] = static_cast<vtkm::FloatDefault>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddField(result, "pointvar", colorMap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchStreamlines(::benchmark::State& state)
|
||||||
|
{
|
||||||
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||||
|
|
||||||
|
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
|
||||||
|
const bool isStructured = static_cast<bool>(state.range(1));
|
||||||
|
const bool isMultiBlock = static_cast<bool>(state.range(2));
|
||||||
|
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(3));
|
||||||
|
|
||||||
|
vtkm::cont::Timer inputGenTimer{ device };
|
||||||
|
inputGenTimer.Start();
|
||||||
|
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
|
||||||
|
inputGenTimer.Stop();
|
||||||
|
|
||||||
|
vtkm::filter::Streamline streamline;
|
||||||
|
streamline.SetStepSize(0.1f);
|
||||||
|
streamline.SetNumberOfSteps(1000);
|
||||||
|
streamline.SetActiveField(PointVectorsName);
|
||||||
|
|
||||||
|
vtkm::cont::Timer totalTimer{ device };
|
||||||
|
vtkm::cont::Timer filterTimer{ device };
|
||||||
|
vtkm::cont::Timer renderTimer{ device };
|
||||||
|
vtkm::cont::Timer writeTimer{ device };
|
||||||
|
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
(void)_;
|
||||||
|
totalTimer.Start();
|
||||||
|
filterTimer.Start();
|
||||||
|
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets;
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
auto input = PartitionedInputDataSet;
|
||||||
|
auto result = RunStreamlinesHelper(streamline, input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto input = InputDataSet;
|
||||||
|
auto result = RunStreamlinesHelper(streamline, input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
filterTimer.Stop();
|
||||||
|
|
||||||
|
renderTimer.Start();
|
||||||
|
auto canvas = RenderDataSets(dataSets, renderAlgo, "pointvar");
|
||||||
|
renderTimer.Stop();
|
||||||
|
|
||||||
|
writeTimer.Start();
|
||||||
|
WriteToDisk(*canvas, renderAlgo, "streamlines", isStructured, isMultiBlock, cycle);
|
||||||
|
writeTimer.Stop();
|
||||||
|
|
||||||
|
totalTimer.Stop();
|
||||||
|
|
||||||
|
state.SetIterationTime(totalTimer.GetElapsedTime());
|
||||||
|
state.counters.insert(
|
||||||
|
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "FilterTime", static_cast<uint32_t>(filterTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "RenderTime", static_cast<uint32_t>(renderTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "WriteTime", static_cast<uint32_t>(writeTimer.GetElapsedTime() * 1000) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchStreamlinesGenerator(::benchmark::internal::Benchmark* bm)
|
||||||
|
{
|
||||||
|
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" });
|
||||||
|
|
||||||
|
std::vector<uint32_t> isStructureds{ false, true };
|
||||||
|
std::vector<uint32_t> isMultiBlocks{ false, true };
|
||||||
|
std::vector<RenderingMode> renderingModes{ RenderingMode::Mesh };
|
||||||
|
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
|
||||||
|
{
|
||||||
|
for (auto& isStructured : isStructureds)
|
||||||
|
{
|
||||||
|
for (auto& isMultiBlock : isMultiBlocks)
|
||||||
|
{
|
||||||
|
for (auto& mode : renderingModes)
|
||||||
|
{
|
||||||
|
bm->Args({ cycle, isStructured, isMultiBlock, static_cast<int>(mode) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_BENCHMARK_APPLY(BenchStreamlines, BenchStreamlinesGenerator);
|
||||||
|
|
||||||
|
vtkm::Vec3f GetSlicePlaneOrigin(const bool isMultiBlock)
|
||||||
|
{
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
auto data = PartitionedInputDataSet;
|
||||||
|
vtkm::Bounds global;
|
||||||
|
global = data.GetPartition(0).GetCoordinateSystem().GetBounds();
|
||||||
|
for (auto i = 1; i < data.GetNumberOfPartitions(); ++i)
|
||||||
|
{
|
||||||
|
auto dataset = data.GetPartition(i);
|
||||||
|
vtkm::Bounds bounds = dataset.GetCoordinateSystem().GetBounds();
|
||||||
|
global.X.Min = vtkm::Min(global.X.Min, bounds.X.Min);
|
||||||
|
global.Y.Min = vtkm::Min(global.Y.Min, bounds.Y.Min);
|
||||||
|
global.Z.Min = vtkm::Min(global.Z.Min, bounds.Z.Min);
|
||||||
|
global.X.Max = vtkm::Min(global.X.Max, bounds.X.Max);
|
||||||
|
global.Y.Max = vtkm::Min(global.Y.Max, bounds.Y.Max);
|
||||||
|
global.Z.Max = vtkm::Min(global.Z.Max, bounds.Z.Max);
|
||||||
|
}
|
||||||
|
return vtkm::Vec3f{ static_cast<vtkm::FloatDefault>((global.X.Max - global.X.Min) / 2.),
|
||||||
|
static_cast<vtkm::FloatDefault>((global.Y.Max - global.Y.Min) / 2.),
|
||||||
|
static_cast<vtkm::FloatDefault>((global.Z.Max - global.Z.Min) / 2.) };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto data = InputDataSet;
|
||||||
|
vtkm::Bounds bounds = data.GetCoordinateSystem().GetBounds();
|
||||||
|
return vtkm::Vec3f{ static_cast<vtkm::FloatDefault>((bounds.X.Max - bounds.X.Min) / 2.),
|
||||||
|
static_cast<vtkm::FloatDefault>((bounds.Y.Max - bounds.Y.Min) / 2.),
|
||||||
|
static_cast<vtkm::FloatDefault>((bounds.Z.Max - bounds.Z.Min) / 2.) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchSlice(::benchmark::State& state)
|
||||||
|
{
|
||||||
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||||
|
|
||||||
|
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
|
||||||
|
const bool isStructured = static_cast<bool>(state.range(1));
|
||||||
|
const bool isMultiBlock = static_cast<bool>(state.range(2));
|
||||||
|
const RenderingMode renderAlgo = static_cast<RenderingMode>(state.range(3));
|
||||||
|
|
||||||
|
vtkm::cont::Timer inputGenTimer{ device };
|
||||||
|
inputGenTimer.Start();
|
||||||
|
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
|
||||||
|
inputGenTimer.Stop();
|
||||||
|
|
||||||
|
vtkm::filter::Slice filter;
|
||||||
|
|
||||||
|
vtkm::cont::Timer totalTimer{ device };
|
||||||
|
vtkm::cont::Timer filterTimer{ device };
|
||||||
|
vtkm::cont::Timer renderTimer{ device };
|
||||||
|
vtkm::cont::Timer writeTimer{ device };
|
||||||
|
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
(void)_;
|
||||||
|
totalTimer.Start();
|
||||||
|
filterTimer.Start();
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets;
|
||||||
|
if (isMultiBlock)
|
||||||
|
{
|
||||||
|
auto input = PartitionedInputDataSet;
|
||||||
|
vtkm::Vec3f origin = GetSlicePlaneOrigin(isMultiBlock);
|
||||||
|
// Set-up implicit function
|
||||||
|
vtkm::Plane plane(origin, vtkm::Plane::Vector{ 1, 1, 1 });
|
||||||
|
filter.SetImplicitFunction(plane);
|
||||||
|
auto result = filter.Execute(input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto input = InputDataSet;
|
||||||
|
vtkm::Vec3f origin = GetSlicePlaneOrigin(isMultiBlock);
|
||||||
|
// Set-up implicit function
|
||||||
|
vtkm::Plane plane(origin, vtkm::Plane::Vector{ 1, 1, 1 });
|
||||||
|
filter.SetImplicitFunction(plane);
|
||||||
|
auto result = filter.Execute(input);
|
||||||
|
dataSets = ExtractDataSets(result);
|
||||||
|
}
|
||||||
|
filterTimer.Stop();
|
||||||
|
|
||||||
|
renderTimer.Start();
|
||||||
|
auto canvas = RenderDataSets(dataSets, renderAlgo, PointScalarsName);
|
||||||
|
renderTimer.Stop();
|
||||||
|
|
||||||
|
writeTimer.Start();
|
||||||
|
WriteToDisk(*canvas, renderAlgo, "slice", isStructured, isMultiBlock, cycle);
|
||||||
|
writeTimer.Stop();
|
||||||
|
|
||||||
|
totalTimer.Stop();
|
||||||
|
|
||||||
|
state.SetIterationTime(totalTimer.GetElapsedTime());
|
||||||
|
state.counters.insert(
|
||||||
|
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "FilterTime", static_cast<uint32_t>(filterTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "RenderTime", static_cast<uint32_t>(renderTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "WriteTime", static_cast<uint32_t>(writeTimer.GetElapsedTime() * 1000) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchSliceGenerator(::benchmark::internal::Benchmark* bm)
|
||||||
|
{
|
||||||
|
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" });
|
||||||
|
|
||||||
|
std::vector<uint32_t> isStructureds{ false, true };
|
||||||
|
std::vector<uint32_t> isMultiBlocks{ false, true };
|
||||||
|
std::vector<RenderingMode> renderingModes{ RenderingMode::RayTrace };
|
||||||
|
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
|
||||||
|
{
|
||||||
|
for (auto& isStructured : isStructureds)
|
||||||
|
{
|
||||||
|
for (auto& isMultiBlock : isMultiBlocks)
|
||||||
|
{
|
||||||
|
for (auto& mode : renderingModes)
|
||||||
|
{
|
||||||
|
bm->Args({ cycle, isStructured, isMultiBlock, static_cast<int>(mode) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_BENCHMARK_APPLY(BenchSlice, BenchSliceGenerator);
|
||||||
|
|
||||||
|
void BenchMeshRendering(::benchmark::State& state)
|
||||||
|
{
|
||||||
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||||
|
|
||||||
|
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
|
||||||
|
const bool isStructured = static_cast<bool>(state.range(1));
|
||||||
|
const bool isMultiBlock = static_cast<bool>(state.range(2));
|
||||||
|
|
||||||
|
vtkm::cont::Timer inputGenTimer{ device };
|
||||||
|
vtkm::cont::Timer renderTimer{ device };
|
||||||
|
vtkm::cont::Timer writeTimer{ device };
|
||||||
|
|
||||||
|
inputGenTimer.Start();
|
||||||
|
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
|
||||||
|
inputGenTimer.Stop();
|
||||||
|
|
||||||
|
vtkm::cont::Timer totalTimer{ device };
|
||||||
|
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
(void)_;
|
||||||
|
|
||||||
|
totalTimer.Start();
|
||||||
|
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets =
|
||||||
|
isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet);
|
||||||
|
|
||||||
|
renderTimer.Start();
|
||||||
|
auto canvas = RenderDataSets(dataSets, RenderingMode::Mesh, PointScalarsName);
|
||||||
|
renderTimer.Stop();
|
||||||
|
|
||||||
|
writeTimer.Start();
|
||||||
|
WriteToDisk(*canvas, RenderingMode::Mesh, "mesh", isStructured, isMultiBlock, cycle);
|
||||||
|
writeTimer.Stop();
|
||||||
|
|
||||||
|
totalTimer.Stop();
|
||||||
|
|
||||||
|
state.SetIterationTime(totalTimer.GetElapsedTime());
|
||||||
|
state.counters.insert(
|
||||||
|
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "FilterTime", 0 },
|
||||||
|
{ "RenderTime", static_cast<uint32_t>(renderTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "WriteTime", static_cast<uint32_t>(writeTimer.GetElapsedTime() * 1000) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchMeshRenderingGenerator(::benchmark::internal::Benchmark* bm)
|
||||||
|
{
|
||||||
|
bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock" });
|
||||||
|
|
||||||
|
std::vector<uint32_t> isStructureds{ false, true };
|
||||||
|
std::vector<uint32_t> isMultiBlocks{ false, true };
|
||||||
|
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
|
||||||
|
{
|
||||||
|
for (auto& isStructured : isStructureds)
|
||||||
|
{
|
||||||
|
for (auto& isMultiBlock : isMultiBlocks)
|
||||||
|
{
|
||||||
|
bm->Args({ cycle, isStructured, isMultiBlock });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_BENCHMARK_APPLY(BenchMeshRendering, BenchMeshRenderingGenerator);
|
||||||
|
|
||||||
|
void BenchVolumeRendering(::benchmark::State& state)
|
||||||
|
{
|
||||||
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||||
|
|
||||||
|
const uint32_t cycle = static_cast<uint32_t>(state.range(0));
|
||||||
|
const bool isStructured = true;
|
||||||
|
const bool isMultiBlock = static_cast<bool>(state.range(1));
|
||||||
|
|
||||||
|
vtkm::cont::Timer inputGenTimer{ device };
|
||||||
|
inputGenTimer.Start();
|
||||||
|
BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim);
|
||||||
|
inputGenTimer.Stop();
|
||||||
|
|
||||||
|
vtkm::cont::Timer totalTimer{ device };
|
||||||
|
vtkm::cont::Timer renderTimer{ device };
|
||||||
|
vtkm::cont::Timer writeTimer{ device };
|
||||||
|
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
(void)_;
|
||||||
|
totalTimer.Start();
|
||||||
|
|
||||||
|
renderTimer.Start();
|
||||||
|
std::vector<vtkm::cont::DataSet> dataSets =
|
||||||
|
isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet);
|
||||||
|
auto canvas = RenderDataSets(dataSets, RenderingMode::Volume, PointScalarsName);
|
||||||
|
renderTimer.Stop();
|
||||||
|
|
||||||
|
writeTimer.Start();
|
||||||
|
WriteToDisk(*canvas, RenderingMode::Volume, "volume", isStructured, isMultiBlock, cycle);
|
||||||
|
writeTimer.Stop();
|
||||||
|
|
||||||
|
totalTimer.Stop();
|
||||||
|
|
||||||
|
state.SetIterationTime(totalTimer.GetElapsedTime());
|
||||||
|
state.counters.insert(
|
||||||
|
{ { "InputGenTime", static_cast<uint32_t>(inputGenTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "FilterTime", 0 },
|
||||||
|
{ "RenderTime", static_cast<uint32_t>(renderTimer.GetElapsedTime() * 1000) },
|
||||||
|
{ "WriteTime", static_cast<uint32_t>(writeTimer.GetElapsedTime() * 1000) } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchVolumeRenderingGenerator(::benchmark::internal::Benchmark* bm)
|
||||||
|
{
|
||||||
|
bm->ArgNames({ "Cycle", "IsMultiBlock" });
|
||||||
|
|
||||||
|
std::vector<uint32_t> isMultiBlocks{ false };
|
||||||
|
for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle)
|
||||||
|
{
|
||||||
|
for (auto& isMultiBlock : isMultiBlocks)
|
||||||
|
{
|
||||||
|
bm->Args({ cycle, isMultiBlock });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_BENCHMARK_APPLY(BenchVolumeRendering, BenchVolumeRenderingGenerator);
|
||||||
|
|
||||||
|
struct Arg : vtkm::cont::internal::option::Arg
|
||||||
|
{
|
||||||
|
static vtkm::cont::internal::option::ArgStatus Number(
|
||||||
|
const vtkm::cont::internal::option::Option& option,
|
||||||
|
bool msg)
|
||||||
|
{
|
||||||
|
bool argIsNum = ((option.arg != nullptr) && (option.arg[0] != '\0'));
|
||||||
|
const char* c = option.arg;
|
||||||
|
while (argIsNum && (*c != '\0'))
|
||||||
|
{
|
||||||
|
argIsNum &= static_cast<bool>(std::isdigit(*c));
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argIsNum)
|
||||||
|
{
|
||||||
|
return vtkm::cont::internal::option::ARG_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
std::cerr << "Option " << option.name << " requires a numeric argument." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vtkm::cont::internal::option::ARG_ILLEGAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OptionIndex
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
HELP,
|
||||||
|
DATASET_DIM,
|
||||||
|
IMAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ParseBenchmarkOptions(int& argc, char** argv)
|
||||||
|
{
|
||||||
|
namespace option = vtkm::cont::internal::option;
|
||||||
|
|
||||||
|
std::vector<option::Descriptor> usage;
|
||||||
|
std::string usageHeader{ "Usage: " };
|
||||||
|
usageHeader.append(argv[0]);
|
||||||
|
usageHeader.append("[input data options] [benchmark options]");
|
||||||
|
usage.push_back({ UNKNOWN, 0, "", "", Arg::None, usageHeader.c_str() });
|
||||||
|
usage.push_back({ UNKNOWN, 0, "", "", Arg::None, "Input data options are:" });
|
||||||
|
usage.push_back({ HELP, 0, "h", "help", Arg::None, " -h, --help\tDisplay this help." });
|
||||||
|
usage.push_back({ UNKNOWN, 0, "", "", Arg::None, Config.Usage.c_str() });
|
||||||
|
usage.push_back({ DATASET_DIM,
|
||||||
|
0,
|
||||||
|
"s",
|
||||||
|
"size",
|
||||||
|
Arg::Number,
|
||||||
|
" -s, --size <N> \tSpecify dataset dimension and "
|
||||||
|
"dataset with NxNxN dimensions is created. "
|
||||||
|
"If not specified, N=128" });
|
||||||
|
usage.push_back({ IMAGE_SIZE,
|
||||||
|
0,
|
||||||
|
"i",
|
||||||
|
"image-size",
|
||||||
|
Arg::Number,
|
||||||
|
" -i, --image-size <N> \tSpecify size of the rendered image."
|
||||||
|
" The image is rendered as a square of size NxN. "
|
||||||
|
"If not specified, N=1024" });
|
||||||
|
usage.push_back({ 0, 0, nullptr, nullptr, nullptr, nullptr });
|
||||||
|
|
||||||
|
option::Stats stats(usage.data(), argc - 1, argv + 1);
|
||||||
|
std::unique_ptr<option::Option[]> options{ new option::Option[stats.options_max] };
|
||||||
|
std::unique_ptr<option::Option[]> buffer{ new option::Option[stats.buffer_max] };
|
||||||
|
option::Parser commandLineParse(usage.data(), argc - 1, argv + 1, options.get(), buffer.get());
|
||||||
|
|
||||||
|
if (options[HELP])
|
||||||
|
{
|
||||||
|
option::printUsage(std::cout, usage.data());
|
||||||
|
// Print google benchmark usage too
|
||||||
|
const char* helpstr = "--help";
|
||||||
|
char* tmpargv[] = { argv[0], const_cast<char*>(helpstr), nullptr };
|
||||||
|
int tmpargc = 2;
|
||||||
|
VTKM_EXECUTE_BENCHMARKS(tmpargc, tmpargv);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (options[DATASET_DIM])
|
||||||
|
{
|
||||||
|
std::istringstream parse(options[DATASET_DIM].arg);
|
||||||
|
parse >> DataSetDim;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DataSetDim = DEFAULT_DATASET_DIM;
|
||||||
|
}
|
||||||
|
if (options[IMAGE_SIZE])
|
||||||
|
{
|
||||||
|
std::istringstream parse(options[IMAGE_SIZE].arg);
|
||||||
|
parse >> ImageSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImageSize = DEFAULT_IMAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Using data set dimensions = " << DataSetDim << std::endl;
|
||||||
|
std::cerr << "Using image size = " << ImageSize << "x" << ImageSize << std::endl;
|
||||||
|
|
||||||
|
// Now go back through the arg list and remove anything that is not in the list of
|
||||||
|
// unknown options or non-option arguments.
|
||||||
|
int destArg = 1;
|
||||||
|
// This is copy/pasted from vtkm::cont::Initialize(), should probably be abstracted eventually:
|
||||||
|
for (int srcArg = 1; srcArg < argc; ++srcArg)
|
||||||
|
{
|
||||||
|
std::string thisArg{ argv[srcArg] };
|
||||||
|
bool copyArg = false;
|
||||||
|
|
||||||
|
// Special case: "--" gets removed by optionparser but should be passed.
|
||||||
|
if (thisArg == "--")
|
||||||
|
{
|
||||||
|
copyArg = true;
|
||||||
|
}
|
||||||
|
for (const option::Option* opt = options[UNKNOWN]; !copyArg && opt != nullptr;
|
||||||
|
opt = opt->next())
|
||||||
|
{
|
||||||
|
if (thisArg == opt->name)
|
||||||
|
{
|
||||||
|
copyArg = true;
|
||||||
|
}
|
||||||
|
if ((opt->arg != nullptr) && (thisArg == opt->arg))
|
||||||
|
{
|
||||||
|
copyArg = true;
|
||||||
|
}
|
||||||
|
// Special case: optionparser sometimes removes a single "-" from an option
|
||||||
|
if (thisArg.substr(1) == opt->name)
|
||||||
|
{
|
||||||
|
copyArg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int nonOpt = 0; !copyArg && nonOpt < commandLineParse.nonOptionsCount(); ++nonOpt)
|
||||||
|
{
|
||||||
|
if (thisArg == commandLineParse.nonOption(nonOpt))
|
||||||
|
{
|
||||||
|
copyArg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copyArg)
|
||||||
|
{
|
||||||
|
if (destArg != srcArg)
|
||||||
|
{
|
||||||
|
argv[destArg] = argv[srcArg];
|
||||||
|
}
|
||||||
|
++destArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc = destArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end anon namespace
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
auto opts = vtkm::cont::InitializeOptions::RequireDevice;
|
||||||
|
|
||||||
|
std::vector<char*> args(argv, argv + argc);
|
||||||
|
vtkm::bench::detail::InitializeArgs(&argc, args, opts);
|
||||||
|
|
||||||
|
// Parse VTK-m options
|
||||||
|
Config = vtkm::cont::Initialize(argc, args.data(), opts);
|
||||||
|
ParseBenchmarkOptions(argc, args.data());
|
||||||
|
|
||||||
|
// This opts chances when it is help
|
||||||
|
if (opts != vtkm::cont::InitializeOptions::None)
|
||||||
|
{
|
||||||
|
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_EXECUTE_BENCHMARKS(argc, args.data());
|
||||||
|
}
|
@ -71,4 +71,5 @@ endif()
|
|||||||
|
|
||||||
if(TARGET vtkm_rendering)
|
if(TARGET vtkm_rendering)
|
||||||
add_benchmark(NAME BenchmarkRayTracing FILE BenchmarkRayTracing.cxx LIBS vtkm_rendering vtkm_source)
|
add_benchmark(NAME BenchmarkRayTracing FILE BenchmarkRayTracing.cxx LIBS vtkm_rendering vtkm_source)
|
||||||
|
add_benchmark(NAME BenchmarkInSitu FILE BenchmarkInSitu.cxx LIBS vtkm_rendering vtkm_source vtkm_filter vtkm_io)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1 +1 @@
|
|||||||
1.7.0-rc1
|
1.7.0
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
#include <vtkm/cont/RuntimeDeviceInformation.h>
|
#include <vtkm/cont/RuntimeDeviceInformation.h>
|
||||||
#include <vtkm/cont/cuda/ErrorCuda.h>
|
#include <vtkm/cont/cuda/ErrorCuda.h>
|
||||||
|
#include <vtkm/cont/cuda/internal/DeviceAdapterTagCuda.h>
|
||||||
#include <vtkm/cont/cuda/internal/RuntimeDeviceConfigurationCuda.h>
|
#include <vtkm/cont/cuda/internal/RuntimeDeviceConfigurationCuda.h>
|
||||||
#include <vtkm/cont/internal/DeviceAdapterTagCuda.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -13,6 +13,7 @@ set(headers
|
|||||||
Source.h
|
Source.h
|
||||||
Tangle.h
|
Tangle.h
|
||||||
Wavelet.h
|
Wavelet.h
|
||||||
|
PerlinNoise.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(device_sources
|
set(device_sources
|
||||||
@ -20,6 +21,7 @@ set(device_sources
|
|||||||
Source.cxx
|
Source.cxx
|
||||||
Tangle.cxx
|
Tangle.cxx
|
||||||
Wavelet.cxx
|
Wavelet.cxx
|
||||||
|
PerlinNoise.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
vtkm_library(NAME vtkm_source
|
vtkm_library(NAME vtkm_source
|
||||||
|
209
vtkm/source/PerlinNoise.cxx
Normal file
209
vtkm/source/PerlinNoise.cxx
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
//============================================================================
|
||||||
|
// 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 <random>
|
||||||
|
|
||||||
|
#include <vtkm/VectorAnalysis.h>
|
||||||
|
#include <vtkm/filter/FilterField.h>
|
||||||
|
#include <vtkm/source/PerlinNoise.h>
|
||||||
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
||||||
|
|
||||||
|
namespace vtkm
|
||||||
|
{
|
||||||
|
namespace source
|
||||||
|
{
|
||||||
|
namespace perlin
|
||||||
|
{
|
||||||
|
struct PerlinNoiseWorklet : public vtkm::worklet::WorkletVisitPointsWithCells
|
||||||
|
{
|
||||||
|
using ControlSignature = void(CellSetIn, FieldInPoint, WholeArrayIn, FieldOut noise);
|
||||||
|
using ExecutionSignature = void(_2, _3, _4);
|
||||||
|
|
||||||
|
VTKM_CONT PerlinNoiseWorklet(vtkm::Id repeat)
|
||||||
|
: Repeat(repeat)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapted from https://adrianb.io/2014/08/09/perlinnoise.html
|
||||||
|
// Archive link: https://web.archive.org/web/20210329174559/https://adrianb.io/2014/08/09/perlinnoise.html
|
||||||
|
template <typename PointVecType, typename PermsPortal, typename OutType>
|
||||||
|
VTKM_EXEC void operator()(const PointVecType& pos, const PermsPortal& perms, OutType& noise) const
|
||||||
|
{
|
||||||
|
vtkm::Id xi = static_cast<vtkm::Id>(pos[0]) % this->Repeat;
|
||||||
|
vtkm::Id yi = static_cast<vtkm::Id>(pos[1]) % this->Repeat;
|
||||||
|
vtkm::Id zi = static_cast<vtkm::Id>(pos[2]) % this->Repeat;
|
||||||
|
vtkm::FloatDefault xf = pos[0] - xi;
|
||||||
|
vtkm::FloatDefault yf = pos[1] - yi;
|
||||||
|
vtkm::FloatDefault zf = pos[2] - zi;
|
||||||
|
vtkm::FloatDefault u = this->Fade(xf);
|
||||||
|
vtkm::FloatDefault v = this->Fade(yf);
|
||||||
|
vtkm::FloatDefault w = this->Fade(zf);
|
||||||
|
|
||||||
|
vtkm::Id aaa, aba, aab, abb, baa, bba, bab, bbb;
|
||||||
|
aaa = perms[perms[perms[xi] + yi] + zi];
|
||||||
|
aba = perms[perms[perms[xi] + this->Increment(yi)] + zi];
|
||||||
|
aab = perms[perms[perms[xi] + yi] + this->Increment(zi)];
|
||||||
|
abb = perms[perms[perms[xi] + this->Increment(yi)] + this->Increment(zi)];
|
||||||
|
baa = perms[perms[perms[this->Increment(xi)] + yi] + zi];
|
||||||
|
bba = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + zi];
|
||||||
|
bab = perms[perms[perms[this->Increment(xi)] + yi] + this->Increment(zi)];
|
||||||
|
bbb = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + this->Increment(zi)];
|
||||||
|
|
||||||
|
vtkm::FloatDefault x1, x2, y1, y2;
|
||||||
|
x1 = vtkm::Lerp(this->Gradient(aaa, xf, yf, zf), this->Gradient(baa, xf - 1, yf, zf), u);
|
||||||
|
x2 =
|
||||||
|
vtkm::Lerp(this->Gradient(aba, xf, yf - 1, zf), this->Gradient(bba, xf - 1, yf - 1, zf), u);
|
||||||
|
y1 = vtkm::Lerp(x1, x2, v);
|
||||||
|
|
||||||
|
x1 =
|
||||||
|
vtkm::Lerp(this->Gradient(aab, xf, yf, zf - 1), this->Gradient(bab, xf - 1, yf, zf - 1), u);
|
||||||
|
x2 = vtkm::Lerp(
|
||||||
|
this->Gradient(abb, xf, yf - 1, zf - 1), this->Gradient(bbb, xf - 1, yf - 1, zf - 1), u);
|
||||||
|
y2 = vtkm::Lerp(x1, x2, v);
|
||||||
|
|
||||||
|
noise = (vtkm::Lerp(y1, y2, w) + OutType(1.0f)) * OutType(0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_EXEC vtkm::FloatDefault Fade(vtkm::FloatDefault t) const
|
||||||
|
{
|
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_EXEC vtkm::Id Increment(vtkm::Id n) const { return (n + 1) % this->Repeat; }
|
||||||
|
|
||||||
|
VTKM_EXEC vtkm::FloatDefault Gradient(vtkm::Id hash,
|
||||||
|
vtkm::FloatDefault x,
|
||||||
|
vtkm::FloatDefault y,
|
||||||
|
vtkm::FloatDefault z) const
|
||||||
|
{
|
||||||
|
switch (hash & 0xF)
|
||||||
|
{
|
||||||
|
case 0x0:
|
||||||
|
return x + y;
|
||||||
|
case 0x1:
|
||||||
|
return -x + y;
|
||||||
|
case 0x2:
|
||||||
|
return x - y;
|
||||||
|
case 0x3:
|
||||||
|
return -x - y;
|
||||||
|
case 0x4:
|
||||||
|
return x + z;
|
||||||
|
case 0x5:
|
||||||
|
return -x + z;
|
||||||
|
case 0x6:
|
||||||
|
return x - z;
|
||||||
|
case 0x7:
|
||||||
|
return -x - z;
|
||||||
|
case 0x8:
|
||||||
|
return y + z;
|
||||||
|
case 0x9:
|
||||||
|
return -y + z;
|
||||||
|
case 0xA:
|
||||||
|
return y - z;
|
||||||
|
case 0xB:
|
||||||
|
return -y - z;
|
||||||
|
case 0xC:
|
||||||
|
return y + x;
|
||||||
|
case 0xD:
|
||||||
|
return -y + z;
|
||||||
|
case 0xE:
|
||||||
|
return y - x;
|
||||||
|
case 0xF:
|
||||||
|
return -y - z;
|
||||||
|
default:
|
||||||
|
return 0; // never happens
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::Id Repeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PerlinNoiseField : public vtkm::filter::FilterField<PerlinNoiseField>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VTKM_CONT PerlinNoiseField(vtkm::IdComponent tableSize, vtkm::Id seed)
|
||||||
|
: TableSize(tableSize)
|
||||||
|
, Seed(seed)
|
||||||
|
{
|
||||||
|
this->GeneratePermutations();
|
||||||
|
this->SetUseCoordinateSystemAsField(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FieldType, typename DerivedPolicy>
|
||||||
|
VTKM_CONT vtkm::cont::DataSet DoExecute(
|
||||||
|
const vtkm::cont::DataSet& input,
|
||||||
|
const FieldType& vtkmNotUsed(field),
|
||||||
|
const vtkm::filter::FieldMetadata& fieldMetadata,
|
||||||
|
vtkm::filter::PolicyBase<DerivedPolicy> vtkmNotUsed(policy))
|
||||||
|
{
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> noise;
|
||||||
|
PerlinNoiseWorklet worklet{ this->TableSize };
|
||||||
|
this->Invoke(
|
||||||
|
worklet, input.GetCellSet(), input.GetCoordinateSystem(), this->Permutations, noise);
|
||||||
|
|
||||||
|
return vtkm::filter::CreateResult(input, noise, this->GetOutputFieldName(), fieldMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VTKM_CONT void GeneratePermutations()
|
||||||
|
{
|
||||||
|
std::mt19937_64 rng;
|
||||||
|
rng.seed(this->Seed);
|
||||||
|
std::uniform_int_distribution<vtkm::Id> distribution(0, this->TableSize - 1);
|
||||||
|
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> perms;
|
||||||
|
perms.Allocate(this->TableSize);
|
||||||
|
auto permsPortal = perms.WritePortal();
|
||||||
|
for (auto i = 0; i < permsPortal.GetNumberOfValues(); ++i)
|
||||||
|
{
|
||||||
|
permsPortal.Set(i, distribution(rng));
|
||||||
|
}
|
||||||
|
this->Permutations.Allocate(2 * this->TableSize);
|
||||||
|
auto permutations = this->Permutations.WritePortal();
|
||||||
|
for (auto i = 0; i < permutations.GetNumberOfValues(); ++i)
|
||||||
|
{
|
||||||
|
permutations.Set(i, permsPortal.Get(i % this->TableSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::IdComponent TableSize;
|
||||||
|
vtkm::Id Seed;
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Permutations;
|
||||||
|
};
|
||||||
|
} // namespace perlin
|
||||||
|
|
||||||
|
vtkm::cont::DataSet PerlinNoise::Execute() const
|
||||||
|
{
|
||||||
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||||
|
|
||||||
|
vtkm::cont::DataSet dataSet;
|
||||||
|
const vtkm::Id3 pdims{ this->Dims + vtkm::Id3{ 1, 1, 1 } };
|
||||||
|
const vtkm::Vec3f spacing(1.0f / static_cast<vtkm::FloatDefault>(this->Dims[0]),
|
||||||
|
1.0f / static_cast<vtkm::FloatDefault>(this->Dims[1]),
|
||||||
|
1.0f / static_cast<vtkm::FloatDefault>(this->Dims[2]));
|
||||||
|
|
||||||
|
|
||||||
|
vtkm::cont::CellSetStructured<3> cellSet;
|
||||||
|
cellSet.SetPointDimensions(pdims);
|
||||||
|
dataSet.SetCellSet(cellSet);
|
||||||
|
vtkm::cont::ArrayHandleUniformPointCoordinates coordinates(pdims, this->Origin, spacing);
|
||||||
|
dataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", coordinates));
|
||||||
|
|
||||||
|
auto tableSize = static_cast<vtkm::IdComponent>(
|
||||||
|
vtkm::Max(this->Dims[0], vtkm::Max(this->Dims[1], this->Dims[2])));
|
||||||
|
perlin::PerlinNoiseField noiseGenerator(tableSize, this->Seed);
|
||||||
|
noiseGenerator.SetOutputFieldName("perlinnoise");
|
||||||
|
dataSet = noiseGenerator.Execute(dataSet);
|
||||||
|
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace source
|
||||||
|
} // namespace vtkm
|
61
vtkm/source/PerlinNoise.h
Normal file
61
vtkm/source/PerlinNoise.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
//============================================================================
|
||||||
|
// 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_PerlinNoise_h
|
||||||
|
#define vtk_m_source_PerlinNoise_h
|
||||||
|
|
||||||
|
#include <vtkm/source/Source.h>
|
||||||
|
|
||||||
|
namespace vtkm
|
||||||
|
{
|
||||||
|
namespace source
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The PerlinNoise source creates a uniform dataset.
|
||||||
|
*
|
||||||
|
* This class generates a uniform grid dataset with a tileable perlin
|
||||||
|
* noise scalar point field.
|
||||||
|
*
|
||||||
|
* The Execute method creates a complete structured dataset that have a
|
||||||
|
* scalar point field named 'perlinnoise'.
|
||||||
|
**/
|
||||||
|
class VTKM_SOURCE_EXPORT PerlinNoise final : public vtkm::source::Source
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
///Construct a PerlinNoise with Cell Dimensions
|
||||||
|
VTKM_CONT
|
||||||
|
PerlinNoise(vtkm::Id3 dims, vtkm::IdComponent seed)
|
||||||
|
: PerlinNoise(dims, vtkm::Vec3f(0), seed)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VTKM_CONT
|
||||||
|
PerlinNoise(vtkm::Id3 dims, vtkm::Vec3f origin, vtkm::IdComponent seed)
|
||||||
|
: Dims(dims)
|
||||||
|
, Origin(origin)
|
||||||
|
, Seed(seed)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::IdComponent GetSeed() const { return this->Seed; }
|
||||||
|
|
||||||
|
void SetSeed(vtkm::IdComponent seed) { this->Seed = seed; }
|
||||||
|
|
||||||
|
vtkm::cont::DataSet Execute() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vtkm::Id3 Dims;
|
||||||
|
vtkm::Vec3f Origin;
|
||||||
|
vtkm::IdComponent Seed;
|
||||||
|
};
|
||||||
|
} //namespace source
|
||||||
|
} //namespace vtkm
|
||||||
|
|
||||||
|
#endif //vtk_m_source_PerlinNoise_h
|
Loading…
Reference in New Issue
Block a user