vtk-m/vtkm/cont/DataSet.h
Kenneth Moreland 47371bb5e6 Add ability to convert fields to known types
In VTK-m we have a constant tension between minimizing the number of
types we have to compile for (to reduce compile times and library size)
and maximizing the number of types that our filters support.
Unfortunately, if you don't compile a filter for a specific array type
(value type and storage), trying to run that filter will simply fail.

To compromise between the two, added methods to `DataSet` and `Field`
that will automatically convert the data in the `Field` arrays to a type
that VTK-m will understand. Although this will cause an extra data copy,
it will at least prevent the program from failing, and thus make it more
feasible to reduce types.
2021-08-19 07:10:20 -06:00

393 lines
12 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.
//============================================================================
#ifndef vtk_m_cont_DataSet_h
#define vtk_m_cont_DataSet_h
#include <vtkm/cont/vtkm_cont_export.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/UnknownArrayHandle.h>
namespace vtkm
{
namespace cont
{
class VTKM_CONT_EXPORT DataSet
{
public:
VTKM_CONT void Clear();
/// Get the number of cells contained in this DataSet
VTKM_CONT vtkm::Id GetNumberOfCells() const;
/// Get the number of points contained in this DataSet
///
/// Note: All coordinate systems for a DataSet are expected
/// to have the same number of points.
VTKM_CONT vtkm::Id GetNumberOfPoints() const;
VTKM_CONT void AddField(const Field& field);
VTKM_CONT
const vtkm::cont::Field& GetField(vtkm::Id index) const;
VTKM_CONT
vtkm::cont::Field& GetField(vtkm::Id index);
VTKM_CONT
bool HasField(const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY) const
{
bool found = false;
this->FindFieldIndex(name, assoc, found);
return found;
}
VTKM_CONT
bool HasCellField(const std::string& name) const
{
bool found = false;
this->FindFieldIndex(name, vtkm::cont::Field::Association::CELL_SET, found);
return found;
}
VTKM_CONT
bool HasPointField(const std::string& name) const
{
bool found = false;
this->FindFieldIndex(name, vtkm::cont::Field::Association::POINTS, found);
return found;
}
/// Returns the field that matches the provided name and association
/// Will return -1 if no match is found
VTKM_CONT
vtkm::Id GetFieldIndex(
const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY) const;
/// Returns the field that matches the provided name and association
/// Will throw an exception if no match is found
//@{
VTKM_CONT
const vtkm::cont::Field& GetField(
const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY) const
{
return this->GetField(this->GetFieldIndex(name, assoc));
}
VTKM_CONT
vtkm::cont::Field& GetField(
const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY)
{
return this->GetField(this->GetFieldIndex(name, assoc));
}
//@}
/// Returns the first cell field that matches the provided name.
/// Will throw an exception if no match is found
//@{
VTKM_CONT
const vtkm::cont::Field& GetCellField(const std::string& name) const
{
return this->GetField(name, vtkm::cont::Field::Association::CELL_SET);
}
VTKM_CONT
vtkm::cont::Field& GetCellField(const std::string& name)
{
return this->GetField(name, vtkm::cont::Field::Association::CELL_SET);
}
//@}
/// Returns the first point field that matches the provided name.
/// Will throw an exception if no match is found
//@{
VTKM_CONT
const vtkm::cont::Field& GetPointField(const std::string& name) const
{
return this->GetField(name, vtkm::cont::Field::Association::POINTS);
}
VTKM_CONT
vtkm::cont::Field& GetPointField(const std::string& name)
{
return this->GetField(name, vtkm::cont::Field::Association::POINTS);
}
//@}
VTKM_CONT
void AddPointField(const std::string& fieldName, const vtkm::cont::UnknownArrayHandle& field)
{
this->AddField(make_FieldPoint(fieldName, field));
}
template <typename T, typename Storage>
VTKM_CONT void AddPointField(const std::string& fieldName,
const vtkm::cont::ArrayHandle<T, Storage>& field)
{
this->AddField(make_FieldPoint(fieldName, field));
}
template <typename T>
VTKM_CONT void AddPointField(const std::string& fieldName, const std::vector<T>& field)
{
this->AddField(
make_Field(fieldName, vtkm::cont::Field::Association::POINTS, field, vtkm::CopyFlag::On));
}
template <typename T>
VTKM_CONT void AddPointField(const std::string& fieldName, const T* field, const vtkm::Id& n)
{
this->AddField(
make_Field(fieldName, vtkm::cont::Field::Association::POINTS, field, n, vtkm::CopyFlag::On));
}
//Cell centered field
VTKM_CONT
void AddCellField(const std::string& fieldName, const vtkm::cont::UnknownArrayHandle& field)
{
this->AddField(make_FieldCell(fieldName, field));
}
template <typename T, typename Storage>
VTKM_CONT void AddCellField(const std::string& fieldName,
const vtkm::cont::ArrayHandle<T, Storage>& field)
{
this->AddField(make_FieldCell(fieldName, field));
}
template <typename T>
VTKM_CONT void AddCellField(const std::string& fieldName, const std::vector<T>& field)
{
this->AddField(
make_Field(fieldName, vtkm::cont::Field::Association::CELL_SET, field, vtkm::CopyFlag::On));
}
template <typename T>
VTKM_CONT void AddCellField(const std::string& fieldName, const T* field, const vtkm::Id& n)
{
this->AddField(make_Field(
fieldName, vtkm::cont::Field::Association::CELL_SET, field, n, vtkm::CopyFlag::On));
}
VTKM_CONT
void AddCoordinateSystem(const vtkm::cont::CoordinateSystem& cs)
{
this->CoordSystems.push_back(cs);
}
VTKM_CONT
bool HasCoordinateSystem(const std::string& name) const
{
return this->GetCoordinateSystemIndex(name) >= 0;
}
VTKM_CONT
const vtkm::cont::CoordinateSystem& GetCoordinateSystem(vtkm::Id index = 0) const;
VTKM_CONT
vtkm::cont::CoordinateSystem& GetCoordinateSystem(vtkm::Id index = 0);
/// Returns the index for the first CoordinateSystem whose
/// name matches the provided string.
/// Will return -1 if no match is found
VTKM_CONT
vtkm::Id GetCoordinateSystemIndex(const std::string& name) const;
/// Returns the first CoordinateSystem that matches the provided name.
/// Will throw an exception if no match is found
//@{
VTKM_CONT
const vtkm::cont::CoordinateSystem& GetCoordinateSystem(const std::string& name) const;
VTKM_CONT
vtkm::cont::CoordinateSystem& GetCoordinateSystem(const std::string& name);
//@}
VTKM_CONT
void SetCellSet(const vtkm::cont::DynamicCellSet& cellSet) { this->CellSet = cellSet; }
template <typename CellSetType>
VTKM_CONT void SetCellSet(const CellSetType& cellSet)
{
VTKM_IS_CELL_SET(CellSetType);
this->CellSet = vtkm::cont::DynamicCellSet(cellSet);
}
VTKM_CONT
const vtkm::cont::DynamicCellSet& GetCellSet() const { return this->CellSet; }
VTKM_CONT
vtkm::cont::DynamicCellSet& GetCellSet() { return this->CellSet; }
VTKM_CONT
vtkm::IdComponent GetNumberOfFields() const
{
return static_cast<vtkm::IdComponent>(this->Fields.size());
}
VTKM_CONT
vtkm::IdComponent GetNumberOfCoordinateSystems() const
{
return static_cast<vtkm::IdComponent>(this->CoordSystems.size());
}
/// Copies the structure i.e. coordinates systems and cellset from the source
/// dataset. The fields are left unchanged.
VTKM_CONT
void CopyStructure(const vtkm::cont::DataSet& source);
/// \brief Convert the structures in this data set to expected types.
///
/// A `DataSet` object can contain data structures of unknown types. Using the data
/// requires casting these data structures to concrete types. It is only possible to
/// check a finite number of data structures.
///
/// The types checked by default are listed in `vtkm/cont/DefaultTypes.h`, which can
/// be configured at compile time. If a `DataSet` contains data not listed there, then
/// it is likely going to cause problems pulling the data back out. To get around this
/// problem, you can call this method to convert the data to a form that is likely to
/// be recognized. This conversion is likely but not guaranteed because not all types
/// are convertable to something recognizable.
///
VTKM_CONT void ConvertToExpected();
VTKM_CONT
void PrintSummary(std::ostream& out) const;
private:
struct FieldCompare
{
using Key = std::pair<std::string, vtkm::cont::Field::Association>;
template <typename T>
bool operator()(const T& a, const T& b) const
{
if (a.first == b.first)
return a.second < b.second && a.second != vtkm::cont::Field::Association::ANY &&
b.second != vtkm::cont::Field::Association::ANY;
return a.first < b.first;
}
};
std::vector<vtkm::cont::CoordinateSystem> CoordSystems;
std::map<FieldCompare::Key, vtkm::cont::Field, FieldCompare> Fields;
vtkm::cont::DynamicCellSet CellSet;
VTKM_CONT
vtkm::Id FindFieldIndex(const std::string& name,
vtkm::cont::Field::Association association,
bool& found) const;
};
} // namespace cont
} // namespace vtkm
//=============================================================================
// Specializations of serialization related classes
/// @cond SERIALIZATION
namespace vtkm
{
namespace cont
{
template <typename FieldTypeList = VTKM_DEFAULT_TYPE_LIST,
typename CellSetTypesList = VTKM_DEFAULT_CELL_SET_LIST>
struct SerializableDataSet
{
SerializableDataSet() = default;
explicit SerializableDataSet(const vtkm::cont::DataSet& dataset)
: DataSet(dataset)
{
}
vtkm::cont::DataSet DataSet;
};
}
} // vtkm::cont
namespace mangled_diy_namespace
{
template <typename FieldTypeList, typename CellSetTypesList>
struct Serialization<vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypesList>>
{
private:
using Type = vtkm::cont::SerializableDataSet<FieldTypeList, CellSetTypesList>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const Type& serializable)
{
const auto& dataset = serializable.DataSet;
vtkm::IdComponent numberOfCoordinateSystems = dataset.GetNumberOfCoordinateSystems();
vtkmdiy::save(bb, numberOfCoordinateSystems);
for (vtkm::IdComponent i = 0; i < numberOfCoordinateSystems; ++i)
{
vtkmdiy::save(bb, dataset.GetCoordinateSystem(i));
}
vtkmdiy::save(bb, dataset.GetCellSet().ResetCellSetList(CellSetTypesList{}));
vtkm::IdComponent numberOfFields = dataset.GetNumberOfFields();
vtkmdiy::save(bb, numberOfFields);
for (vtkm::IdComponent i = 0; i < numberOfFields; ++i)
{
vtkmdiy::save(bb, dataset.GetField(i));
}
}
static VTKM_CONT void load(BinaryBuffer& bb, Type& serializable)
{
auto& dataset = serializable.DataSet;
dataset = {}; // clear
vtkm::IdComponent numberOfCoordinateSystems = 0;
vtkmdiy::load(bb, numberOfCoordinateSystems);
for (vtkm::IdComponent i = 0; i < numberOfCoordinateSystems; ++i)
{
vtkm::cont::CoordinateSystem coords;
vtkmdiy::load(bb, coords);
dataset.AddCoordinateSystem(coords);
}
vtkm::cont::DynamicCellSetBase<CellSetTypesList> cells;
vtkmdiy::load(bb, cells);
dataset.SetCellSet(vtkm::cont::DynamicCellSet(cells));
vtkm::IdComponent numberOfFields = 0;
vtkmdiy::load(bb, numberOfFields);
for (vtkm::IdComponent i = 0; i < numberOfFields; ++i)
{
vtkm::cont::Field field;
vtkmdiy::load(bb, field);
dataset.AddField(field);
}
}
};
} // diy
/// @endcond SERIALIZATION
#endif //vtk_m_cont_DataSet_h