3.6. Unknown Cell Sets

viskores::cont::DataSet must hold a viskores::cont::CellSet object, but it cannot know its specific type at compile time. To manage storing viskores::cont::CellSet objects without knowing their types, viskores::cont::DataSet actually holds a reference using viskores::cont::UnknownCellSet. viskores::cont::UnknownCellSet is a simple polymorphic container that stores a reference to a viskores::cont::CellSet of unknown type.

class UnknownCellSet

A CellSet of an unknown type.

UnknownCellSet holds a CellSet object using runtime polymorphism to manage the dynamic type rather than compile-time templates. This adds a programming convenience that helps avoid a proliferation of templates.

To interface between the runtime polymorphism and the templated algorithms in Viskores, UnknownCellSet contains a method named CastAndCallForTypes that determines the correct type from some known list of types. This mechanism is used internally by Viskores’s worklet invocation mechanism to determine the type when running algorithms.

If the UnknownCellSet is used in a context where the possible cell set types can be whittled down to a finite list, you can specify lists of cell set types using the ResetCellSetList method. This will convert this object to an UncertainCellSet of the given types. In cases where a finite set of types are needed but there is no subset, VISKORES_DEFAULT_CELL_SET_LIST

Subclassed by viskores::cont::UncertainCellSet< CellSetList >

It is possible to create an empty viskores::cont::UnknownCellSet. You can use the viskores::cont::UnknownCellSet::IsValid() function to query whether an viskores::cont::UnknownCellSet holds a valid viskores::cont::CellSet. Performing operations on an invalid viskores::cont::UnknownCellSet can lead to unexpected behavior.

3.6.1. Generic Operations

Some cell set operations in Viskores require a specific, concrete class of viskores::cont::CellSet. But viskores::cont::UnknownCellSet provides several functions that allow you to operate on a cell set without knowing the exact type.

inline bool viskores::cont::UnknownCellSet::IsValid() const

Returns whether a cell set is stored in this UnknownCellSet.

If the UnknownCellSet is constructed without a CellSet, it will not have an underlying type, and therefore the operations will be invalid.

inline viskores::cont::CellSet *viskores::cont::UnknownCellSet::GetCellSetBase()

Returns a pointer to the CellSet base class.

inline const viskores::cont::CellSet *viskores::cont::UnknownCellSet::GetCellSetBase() const
UnknownCellSet viskores::cont::UnknownCellSet::NewInstance() const

Create a new cell set of the same type as this cell set.

This method creates a new cell set that is the same type as this one and returns a new UnknownCellSet for it. This method is convenient when creating output cell sets that should be the same type as the input cell set.

std::string viskores::cont::UnknownCellSet::GetCellSetName() const

Returns the name of the cell set type stored in this class.

Returns an empty string if no cell set is stored.

inline viskores::Id viskores::cont::UnknownCellSet::GetNumberOfCells() const

Returns the number of cells in the cell set.

inline viskores::Id viskores::cont::UnknownCellSet::GetNumberOfPoints() const

Returns the number of points in the cell set.

inline viskores::UInt8 viskores::cont::UnknownCellSet::GetCellShape(viskores::Id id) const

Given the index of a cell, returns the identifier for the cell shape.

inline viskores::IdComponent viskores::cont::UnknownCellSet::GetNumberOfPointsInCell(viskores::Id id) const

Given the index of a cell, returns the number of points incident on that cell.

inline void viskores::cont::UnknownCellSet::GetCellPointIds(viskores::Id id, viskores::Id *ptids) const

Provides the indices for that the cell is incident to.

Parameters:
  • id – The index of a cell

  • ptids – An array to store the incident point ids. The array should be sized based on GetNumberOfPointsInCell()

inline void viskores::cont::UnknownCellSet::DeepCopyFrom(const CellSet *src)

Copy the connectivity arrays from the provided UnknownCellSet to this one.

void viskores::cont::UnknownCellSet::PrintSummary(std::ostream &os) const

Prints to the provided stream a summary of the contents of the cell set.

It is common to provide std::cout to print the summary to standard output.

inline void viskores::cont::UnknownCellSet::ReleaseResourcesExecution()

Removes any data stored on any device associated with the cell set.

The data for the cell set will still be available, but may need to be loaded back on a device before an operation. This method has no effect if called on an invalid UnknownCellSet.

3.6.2. Casting to Known Types

There are many operations in Viskores that need to know the specific type of cell set. To perform one of these types of operation, you need to retrieve the data as a viskores::cont::CellSet concrete subclass. If you happen to know (or can guess) the type, you can use the viskores::cont::UnknownCellSet::AsCellSet() method to retrieve the cell set as a specific type. You can pass in a reference to a cell set object of the desired type to viskores::cont::UnknownCellSet::AsCellSet(). You can also call viskores::cont::UnknownCellSet::AsCellSet() with no arguments and the cast cell set will be returned, but in this case you must specify the desired type with a template argument.

template<typename CellSetType>
inline void viskores::cont::UnknownCellSet::AsCellSet(CellSetType &cellSet) const

Get the cell set as a known type.

Returns this cell set cast appropriately and stored in the given CellSet type. Throws an ErrorBadType if the stored cell set cannot be stored in the given cell set type. Use the CanConvert() method to determine if the cell set can be returned with the given type.

template<typename CellSetType>
inline CellSetType viskores::cont::UnknownCellSet::AsCellSet() const

Get the cell set as a known type.

Returns this cell set cast appropriately and stored in the given CellSet type. Throws an ErrorBadType if the stored cell set cannot be stored in the given cell set type. Use the CanConvert() method to determine if the cell set can be returned with the given type.

Example 3.55 Retrieving a cell set of a known type from viskores::cont::UnknownCellSet.
1  viskores::cont::CellSetExplicit<> cellSet;
2  unknownCells.AsCellSet(cellSet);
3
4  // This is an equivalent way to get the cell set.
5  auto cellSet2 = unknownCells.AsCellSet<viskores::cont::CellSetExplicit<>>();

If the viskores::cont::UnknownCellSet cannot store its cell set in the type given to viskores::cont::UnknownCellSet::AsCellSet(), it will throw an exception. Thus, you should not use viskores::cont::UnknownCellSet::AsCellSet() with types that you are not sure about. Use the viskores::cont::UnknownCellSet::CanConvert() method to determine if a given viskores::cont::CellSet type will work with viskores::cont::UnknownCellSet::AsCellSet().

template<typename CellSetType>
inline bool viskores::cont::UnknownCellSet::CanConvert() const

Returns true if this cell set can be retrieved as the given type.

This method will return true if calling AsCellSet() of the given type will succeed. This result is similar to IsType(), and if IsType() returns true, then this will return true. However, this method will also return true for other types where automatic conversions are made.

Example 3.56 Querying whether a given viskores::cont::CellSet can be retrieved from an viskores::cont::UnknownCellSet.
 1VISKORES_CONT viskores::Id3 Get3DPointDimensions(
 2  const viskores::cont::UnknownCellSet& unknownCellSet)
 3{
 4  if (unknownCellSet.CanConvert<viskores::cont::CellSetStructured<3>>())
 5  {
 6    viskores::cont::CellSetStructured<3> cellSet;
 7    unknownCellSet.AsCellSet(cellSet);
 8    return cellSet.GetPointDimensions();
 9  }
10  else if (unknownCellSet.CanConvert<viskores::cont::CellSetStructured<2>>())
11  {
12    viskores::cont::CellSetStructured<2> cellSet;
13    unknownCellSet.AsCellSet(cellSet);
14    viskores::Id2 dims = cellSet.GetPointDimensions();
15    return viskores::Id3{ dims[0], dims[1], 1 };
16  }
17  else
18  {
19    return viskores::Id3{ unknownCellSet.GetNumberOfPoints(), 1, 1 };
20  }
21}

By design, viskores::cont::UnknownCellSet::CanConvert() will return true for types that are not actually stored in the viskores::cont::UnknownCellSet but can be retrieved. If you need to know specifically what type is stored in the viskores::cont::UnknownCellSet, you can use the viskores::cont::UnknownCellSet::IsType() method instead. You can also use viskores::cont::UnknownCellSet::GetCellSetName() for debugging purposes.

template<typename CellSetType>
inline bool viskores::cont::UnknownCellSet::IsType() const

Returns true if this cell set matches the CellSetType template argument.

Common Errors

viskores::cont::UnknownCellSet::CanConvert() is almost always safer to use than viskores::cont::UnknownCellSet::IsType() or its similar methods. Even though viskores::cont::UnknownCellSet::IsType() reflects the actual cell set type, viskores::cont::UnknownCellSet::CanConvert() better describes how viskores::cont::UnknownCellSet will behave.

3.6.3. Casting to a List of Potential Types

Using viskores::cont::UnknownCellSet::AsCellSet() is fine as long as the correct types are known, but often times they are not. For this use case viskores::cont::UnknownCellSet has a method named viskores::cont::UnknownCellSet::CastAndCallForTypes() that attempts to cast the cell set to some set of types.

template<typename CellSetList, typename Functor, typename ...Args>
void viskores::cont::UnknownCellSet::CastAndCallForTypes(Functor &&functor, Args&&... args) const

Call a functor using the underlying cell set type.

CastAndCallForTypes attemts to cast the held cell set to a specific type and then calls the given functor with the cast cell set. You must specify the CellSetList (in a viskores::List) as a template argument.

After the functor argument, you may add any number of arguments that will be passed to the functor after the converted cell set.

The viskores::cont::UnknownCellSet::CastAndCallForTypes() method accepts a functor to run on the appropriately cast cell set. The functor must have an overloaded const parentheses operator that accepts a viskores::cont::CellSet of the appropriate type. You also have to specify a template parameter that specifies a viskores::List of cell set types to. The macro VISKORES_DEFAULT_CELL_SET_LIST is often used when nothing more specific is known. The macros VISKORES_DEFAULT_CELL_SET_LIST_STRUCTURED and VISKORES_DEFAULT_CELL_SET_LIST_UNSTRUCTURED are also useful when you want to operate on only structured or unstructured cell sets.

VISKORES_DEFAULT_CELL_SET_LIST

A list of cell set types to use for unknown cell sets.

This macro resolves to a viskores::List filled with concrete subclasses of viskores::cont::CellSet. These are the default cell types checked during a cast and call operation on an unknown cell set. Filters that do not have restrictions on the types of cells they operate on should support the cell set types in this list.

VISKORES_DEFAULT_CELL_SET_LIST_STRUCTURED

A list of structured cell set types to use for unknown cell sets.

This macro resolves to a viskores::List filled with resolved types of the viskores::cont::CellSetStructured template. Filters that only operate on structured data or have special cases for structured data can use this list in a cast and call to check for structured types.

VISKORES_DEFAULT_CELL_SET_LIST_UNSTRUCTURED

A list of unstructured cell set types to use for unknown cell sets.

This macro resolves to a viskores::List filled with concrete subclasses of viskores::cont::CellSet. Typically, this list contains the types in VISKORES_DEFAULT_CELL_SET_LIST minus the structured cell sets. Filters that have special cases for structured data can use this list in a cast and call to cover the more general unstructured cases.

 1struct Get3DPointDimensionsFunctor
 2{
 3  template<viskores::IdComponent Dims>
 4  VISKORES_CONT void operator()(const viskores::cont::CellSetStructured<Dims>& cellSet,
 5                                viskores::Id3& outDims) const
 6  {
 7    viskores::Vec<viskores::Id, Dims> pointDims = cellSet.GetPointDimensions();
 8    for (viskores::IdComponent d = 0; d < Dims; ++d)
 9    {
10      outDims[d] = pointDims[d];
11    }
12  }
13
14  VISKORES_CONT void operator()(const viskores::cont::CellSet& cellSet,
15                                viskores::Id3& outDims) const
16  {
17    outDims[0] = cellSet.GetNumberOfPoints();
18  }
19};
20
21VISKORES_CONT viskores::Id3 Get3DPointDimensions(
22  const viskores::cont::UnknownCellSet& unknownCellSet)
23{
24  viskores::Id3 dims(1);
25  unknownCellSet.CastAndCallForTypes<VISKORES_DEFAULT_CELL_SET_LIST>(
26    Get3DPointDimensionsFunctor{}, dims);
27  return dims;
28}

Did You Know?

The first (required) argument to viskores::cont::UnknownCellSet::CastAndCallForTypes() is the functor to call with the cell set. You can supply any number of optional arguments after that. Those arguments will be passed directly to the functor. This makes it easy to pass state to the functor.

Did You Know?

When an viskores::cont::UnknownCellSet is used in place of an viskores::cont::CellSet as an argument to a worklet invocation, it will internally use viskores::cont::UnknownCellSet::CastAndCallForTypes() to attempt to call the worklet with an viskores::cont::CellSet of the correct type.

viskores::cont::UnknownCellSet has a simple subclass named viskores::cont::UncertainCellSet for use when you can narrow the cell set to a finite set of types. viskores::cont::UncertainCellSet has a template parameter that must be specified: a viskores::List of cell set types. The viskores::cont::UncertainCellSet::CastAndCall() method behaves the same as viskores::cont::UnknownCellSet::CastAndCallForTypes() except that you do not have to specify the types to try. Instead, the types are taken from the template parameters of the viskores::cont::UncertainCellSet itself.

template<typename CellSetList>
class UncertainCellSet : public viskores::cont::UnknownCellSet

A CellSet of an uncertain type.

UncertainCellSet holds a CellSet object using runtime polymorphism to manage different types. It behaves like its superclass, UnknownCellSet, except that it also contains a template parameter that provides a viskores::List of potential cell set types.

These potental types come into play when the CastAndCall method is called (or the UncertainCellSet is used in the viskores::cont::CastAndCall function). In this case, the CastAndCall will search for CellSets of types that match this list.

Both UncertainCellSet and UnknownCellSet have a method named ResetCellSetList that redefines the list of potential cell sets by returning a new UncertainCellSet containing the same CellSet but with the new cell set type list.

Public Functions

inline Thisclass NewInstance() const

Create a new cell set of the same type as this.

This method creates a new cell set that is the same type as this one and returns a new UncertainCellSet for it.

template<typename Functor, typename ...Args>
inline void CastAndCall(Functor &&functor, Args&&... args) const

Call a functor using the underlying cell set type.

CastAndCall attempts to cast the held cell set to a specific type, and then calls the given functor with the cast cell set.

Example 3.58 Using viskores::cont::UncertainCellSet to cast and call a functor.
1  using StructuredCellSetList = viskores::List<viskores::cont::CellSetStructured<1>,
2                                               viskores::cont::CellSetStructured<2>,
3                                               viskores::cont::CellSetStructured<3>>;
4  viskores::cont::UncertainCellSet<StructuredCellSetList> uncertainCellSet(
5    unknownCellSet);
6  uncertainCellSet.CastAndCall(Get3DPointDimensionsFunctor{}, dims);

Did You Know?

Like with viskores::cont::UnknownCellSet, if an viskores::cont::UncertainCellSet is used in a worklet invocation, it will internally use viskores::cont::UncertainCellSet::CastAndCall(). This provides a convenient way to specify what cell set types the invoker should try.

Both viskores::cont::UnknownCellSet and viskores::cont::UncertainCellSet provide a method named viskores::cont::UnknownCellSet::ResetCellSetList() to redefine the types to try. It has a template parameter that is the viskores::List of cell sets. viskores::cont::UnknownCellSet::ResetCellSetList() returns a new viskores::cont::UncertainCellSet with the given types. This is a convenient way to pass these types to functions.

template<typename NewCellSetList>
viskores::cont::UncertainCellSet<NewCellSetList> viskores::cont::UnknownCellSet::ResetCellSetList() const
template<typename NewCellSetList>
viskores::cont::UncertainCellSet<NewCellSetList> viskores::cont::UnknownCellSet::ResetCellSetList(NewCellSetList) const

Assigns potential cell set types.

Calling this method will return an UncertainCellSet with the provided cell set list. The returned object will hold the same CellSet, but CastAndCall’s on the returned object will be constrained to the given types.

Example 3.59 Resetting the types of an viskores::cont::UnknownCellSet.
1  using StructuredCellSetList = viskores::List<viskores::cont::CellSetStructured<1>,
2                                               viskores::cont::CellSetStructured<2>,
3                                               viskores::cont::CellSetStructured<3>>;
4  viskores::cont::Invoker invoke;
5  invoke(
6    MyWorklet{}, unknownCellSet.ResetCellSetList<StructuredCellSetList>(), outArray);

Common Errors

Because it returns a viskores::cont::UncertainCellSet, you need to include viskores/cont/UncertainCellSet.h if you use viskores::cont::UnknownCellSet::ResetCellSetList(). This is true even if you do not directly use the returned object.