vtk-m/examples/clipping/Clipping.cxx
2015-09-16 10:07:25 -04:00

301 lines
9.8 KiB
C++

//============================================================================
// 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.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <stdexcept>
#include <boost/lexical_cast.hpp>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/worklet/Clip.h>
typedef vtkm::Vec<vtkm::Float32, 3> FloatVec3;
template<typename T>
inline void flipEndianness(T* buffer, vtkm::Id size)
{
for (vtkm::Id i = 0; i < size; ++i)
{
T val = buffer[i];
vtkm::UInt8 *bytes = reinterpret_cast<vtkm::UInt8*>(&val);
std::reverse(bytes, bytes + sizeof(T));
buffer[i] = val;
}
}
template<typename T, typename DeviceAdapter>
inline vtkm::cont::ArrayHandle<vtkm::Float32> LoadBinaryPointDataImpl(
std::ifstream &fstream, vtkm::Id numPoints, T, DeviceAdapter)
{
vtkm::cont::ArrayHandle<vtkm::Float32> result;
std::vector<T> buffer(static_cast<size_t>(numPoints));
fstream.read(reinterpret_cast<char*>(&buffer[0]),
numPoints * static_cast<vtkm::Id>(sizeof(T)));
flipEndianness(&buffer[0], numPoints);
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Copy(
vtkm::cont::make_ArrayHandleCast(vtkm::cont::make_ArrayHandle(buffer), vtkm::Float32()),
result);
return result;
}
template<typename DeviceAdapter>
inline vtkm::cont::ArrayHandle<vtkm::Float32> LoadBinaryPointData(
std::ifstream &fstream, vtkm::Id numPoints, std::string type, DeviceAdapter)
{
if (type == "short")
{
return LoadBinaryPointDataImpl(fstream, numPoints, short(), DeviceAdapter());
}
else if (type == "float")
{
return LoadBinaryPointDataImpl(fstream, numPoints, vtkm::Float32(), DeviceAdapter());
}
else
{
throw std::runtime_error("only short and float types supported");
}
return vtkm::cont::ArrayHandle<vtkm::Float32>();
}
template <typename DeviceAdapter>
vtkm::cont::DataSet LoadVtkLegacyStructuredPoints(const char *fname, DeviceAdapter)
{
vtkm::Id3 dim;
FloatVec3 spacing, origin;
vtkm::cont::ArrayHandle<vtkm::Float32> scalars;
std::ifstream vtkfile;
vtkfile.open(fname);
std::string tag;
std::getline(vtkfile, tag); // version comment
std::getline(vtkfile, tag); // datset name
vtkfile >> tag;
if (tag != "BINARY")
{
throw std::runtime_error("only binary format supported");
}
for (;;)
{
vtkfile >> tag;
if (tag == "DATASET")
{
std::string dataset;
vtkfile >> dataset;
if (dataset != "STRUCTURED_POINTS")
{
throw std::runtime_error("expecting structured dataset");
}
}
else if (tag == "DIMENSIONS")
{
vtkfile >> dim[0] >> dim[1] >> dim[2];
}
else if (tag == "SPACING")
{
vtkfile >> spacing[0] >> spacing[1] >> spacing[2];
}
else if (tag == "ORIGIN")
{
vtkfile >> origin[0] >> origin[1] >> origin[2];
}
else if (tag == "POINT_DATA")
{
vtkm::Id numPoints;
std::string type;
vtkfile >> numPoints;
vtkfile >> tag;
if (tag != "SCALARS")
{
throw std::runtime_error("only scalars supported for point data");
}
vtkfile >> tag >> type >> std::ws;
std::getline(vtkfile, tag); // LOOKUP_TABLE default
scalars = LoadBinaryPointData(vtkfile, numPoints, type, DeviceAdapter());
break;
}
}
vtkfile.close();
vtkm::cont::CellSetStructured<3> cs("cells");
cs.SetPointDimensions(vtkm::make_Vec(dim[0], dim[1], dim[2]));
vtkm::cont::DataSet ds;
ds.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", 1, dim, origin,
spacing));
ds.AddField(vtkm::cont::Field("scalars", 1, vtkm::cont::Field::ASSOC_POINTS,
scalars));
ds.AddCellSet(cs);
return ds;
}
void WriteVtkLegacyUnstructuredGrid(const char *fname, const vtkm::cont::DataSet &ds)
{
std::ofstream vtkfile;
vtkfile.open(fname);
vtkfile << "# vtk DataFile Version 3.0" << std::endl;
vtkfile << "vtkm_clip_output" << std::endl;
vtkfile << "BINARY" << std::endl << "DATASET UNSTRUCTURED_GRID" << std::endl;
vtkm::cont::CoordinateSystem coords = ds.GetCoordinateSystem();
vtkm::Id numPoints = coords.GetData().GetNumberOfValues();
vtkfile << "POINTS " << numPoints << " float" << std::endl;
{
vtkm::cont::ArrayHandle<FloatVec3> coordinates =
coords.GetData().CastToArrayHandle(FloatVec3(), VTKM_DEFAULT_STORAGE_TAG());
std::vector<FloatVec3> buffer(static_cast<size_t>(numPoints));
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(coordinates.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(coordinates.GetPortalConstControl()),
buffer.begin());
flipEndianness(reinterpret_cast<vtkm::Float32*>(&buffer[0]), numPoints * 3);
vtkfile.write(reinterpret_cast<const char*>(&buffer[0]),
numPoints * static_cast<vtkm::Id>(sizeof(FloatVec3)));
}
vtkfile << std::endl;
vtkm::cont::CellSetExplicit<> cse =
ds.GetCellSet().CastTo<vtkm::cont::CellSetExplicit<> >();
vtkm::Id numCells = cse.GetNumberOfCells();
{
std::vector<int> idxBuffer, shapeBuffer;
idxBuffer.reserve(static_cast<size_t>(numCells * 4));
shapeBuffer.reserve(static_cast<size_t>(numCells));
vtkm::Vec<vtkm::Id, 8> pointIndices;
for (vtkm::Id i = 0; i < numCells; ++i)
{
vtkm::Id numCellPoints = cse.GetNumberOfPointsInCell(i);
idxBuffer.push_back(static_cast<int>(numCellPoints));
cse.GetIndices(i, pointIndices);
for (vtkm::IdComponent j = 0; j < numCellPoints; ++j)
{
idxBuffer.push_back(static_cast<int>(pointIndices[j]));
}
shapeBuffer.push_back(static_cast<int>(cse.GetCellShape(i)));
}
vtkm::Id numIndices = static_cast<vtkm::Id>(idxBuffer.size());
vtkfile << "CELLS " << numCells << " " << numIndices << std::endl;
flipEndianness(&idxBuffer[0], numIndices);
vtkfile.write(reinterpret_cast<const char*>(&idxBuffer[0]),
numIndices * static_cast<vtkm::Id>(sizeof(idxBuffer[0])));
vtkfile << std::endl;
vtkfile << "CELL_TYPES " << numCells << std::endl;
flipEndianness(&shapeBuffer[0], numCells);
vtkfile.write(reinterpret_cast<const char*>(&shapeBuffer[0]),
numCells * static_cast<vtkm::Id>(sizeof(shapeBuffer[0])));
}
vtkfile << std::endl;
vtkm::cont::Field field = ds.GetField(0);
vtkfile << "POINT_DATA " << numPoints << std::endl
<< "SCALARS " << field.GetName() << " float" << std::endl
<< "LOOKUP_TABLE default" << std::endl;
{
vtkm::cont::ArrayHandle<vtkm::Float32> scalars =
field.GetData().CastToArrayHandle(vtkm::Float32(), VTKM_DEFAULT_STORAGE_TAG());
std::vector<vtkm::Float32> buffer(static_cast<size_t>(numPoints));
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(scalars.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(scalars.GetPortalConstControl()),
buffer.begin());
flipEndianness(&buffer[0], numPoints);
vtkfile.write(reinterpret_cast<const char*>(&buffer[0]),
numPoints * static_cast<vtkm::Id>(sizeof(vtkm::Float32)));
}
vtkfile << std::endl;
vtkfile.close();
}
int main(int argc, char *argv[])
{
if (argc != 4)
{
std::cout << "Usage: " << std::endl
<< "$ " << argv[0]
<< " <vtk_structure_points> <isoval> <vtk_unstructured_grid>"
<< std::endl;
return 1;
}
typedef VTKM_DEFAULT_DEVICE_ADAPTER_TAG DeviceAdapter;
std::cout << "Device Adapter Id: "
<< vtkm::cont::internal::DeviceAdapterTraits<DeviceAdapter>::GetId()
<< std::endl;
vtkm::cont::DataSet input = LoadVtkLegacyStructuredPoints(argv[1], DeviceAdapter());
vtkm::Float32 clipValue = boost::lexical_cast<vtkm::Float32>(argv[2]);
vtkm::worklet::Clip<DeviceAdapter> clip;
vtkm::cont::Timer<DeviceAdapter> total;
vtkm::cont::Timer<DeviceAdapter> timer;
vtkm::cont::CellSetExplicit<> outputCellSet =
clip.Run(input.GetCellSet(0), input.GetField(0).GetData(), clipValue);
vtkm::Float64 clipTime = timer.GetElapsedTime();
timer.Reset();
vtkm::cont::DynamicArrayHandle coords =
clip.ProcessField(input.GetCoordinateSystem(0).GetData());
vtkm::Float64 processCoordinatesTime = timer.GetElapsedTime();
timer.Reset();
vtkm::cont::DynamicArrayHandle scalars =
clip.ProcessField(input.GetField(0).GetData());
vtkm::Float64 processScalarsTime = timer.GetElapsedTime();
vtkm::Float64 totalTime = total.GetElapsedTime();
std::cout << "Timings: " << std::endl
<< "clip: " << clipTime << std::endl
<< "process coordinates: " << processCoordinatesTime << std::endl
<< "process scalars: " << processScalarsTime << std::endl
<< "Total: " << totalTime << std::endl;
vtkm::cont::DataSet output;
output.AddField(vtkm::cont::Field("scalars", 1, vtkm::cont::Field::ASSOC_POINTS,
scalars));
output.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", 1, coords));
output.AddCellSet(outputCellSet);
WriteVtkLegacyUnstructuredGrid(argv[3], output);
return 0;
}