Cell Type Tags

From Daxtoolkit
Jump to: navigation, search

This document describes a new design of how we identify, template and implement cells in Dax. The new design uses tags as the main mechanism for specifying cell types.

Current implementation and motivation

The current implementation defines cell objects in the execution environment. Each object is an independent class. There is no class hierarchy, but the classes are expected to share a common interface for compile time polymorphism and by convention all have names starting with Cell (i.e. CellVoxel, CellTriangle, CellHexahedron, etc.). Each object is functional in that the objects contain state describing the instance of a particular cell and methods for querying and manipulating it.

These cell objects are also used as template parameters for other objects. Most notably, they are a template parameter for unstructured grids. For example, to define an unstructured grid of hexahedra, the declaration is:

dax::cont::UnstructuredGrid<dax::exec::CellHexahedron> grid;

Cell objects are also frequently template parameters to worklet functions to modify their behavior based on grid type.

We have run into two issues with the current design. The first is a style issue in that control objects, such as UnstructuredGrid, are being templates on execution objects. It is a troubling and confusing mashup of the APIs for the two environments that are otherwise expected to be completely separate.

The second issue is a problem with using cell objects to template worklet functions when the details of the cell are not required within the actual function. Consider, for example, the declaration of the ThresholdClassify worklet:

  template<typename CellType>
  DAX_EXEC_EXPORT
  dax::Id operator()(const CellType&,
      const dax::Tuple<ValueType,CellType::NUM_POINTS> &values) const

Note that the first argument, which accepts a cell, is not actually used in the function. The argument exists only to resolve the CellType template parameter. This means the system will incur the overhead to create an instance of a cell even if that instance is never actually used.

Proposed solution

The proposed solution is three parts. First, create a set of tags in the Dax package that represent a cell type. Second, convert the cell classes to be specializations of a class template. Third, make a CellTraits class provides the basic static properties of the cell.

Cell tags

The cell tags classes are defined in the dax namespace and located in a header like Cell.h or CellTags.h. They are simple empty struct declarations like the following.

namespace dax {

struct CellTagVoxel { }
struct CellTagTriangle { }
struct CellTagHexahedron {  }
...

Templated cell classes

The header file dax/exec/Cell.h will contain an actual template declaration like the following.

namespace dax {
namespace exec {

template<class CellTag> class Cell;

}
}

By design, the template is not implemented. All implementations are specializations of this template. So, for example, what was once

class CellHexahedron

becomes

template<>
class Cell<dax::CellTagHexahedron>

Cell traits

Finally, a cell traits class is necessary to provide the basic static information about cells, particularly in the control environment that does not have the implementations of the cell classes. A simple implementation would get the values from the cell classes themselves (decoupling the direct access) although it might also be feasible to go the other way around.

template<class CellTag>
struct CellTraits {
  const static dax::Id NUM_POINTS = dax::exec::Cell<CellType>::NUM_POINTS;
  const static dax::Id TOPOLOGICAL_DIMENSIONS = 
      dax::exec::Cell<CellType>::TOPOLOGICAL_DIMENSIONS;
};

Advantages

The advantage of the tag approach is that it fixes the two aforementioned problems. dax::cont::UnstructuredGrid can now be templates on the tag in the dax namespace rather than the cell class in the dax::exec namespace. Also, worklets can be templates on the cell tag so that the cell class does not have to be constructed.

This tag approach is also consistent with previous changes with the device adapter and array container. Changing to templating on tags is generally leading to cleaner code.

Alternate approach

A slightly different approach is to leave the cell classes the way they are and have another traits-like class choose the appropriate cell class based on the tag. Something like

template<class CellTag> struct CellChooser;

template<> struct CellChooser<dax::CellTagHexahedron> {
  typedef dax::exec::CellHexahedron Type;
};

The advantage of this approach is that if you reference a specific cell type, you can do so simply with the sell type (e.g. dax::exec::CellHexahedron) rather than the templates function (e.g. dax::exec::Cell<dax::CellTagHexahedron>), which would be marginally shorter.

However, I am not thrilled with the approach. It just "seems" backwards to me. besides, if you have to template based on the tag, then your syntax suddenly becomes rather strange (e.g. dax::exec::CellChooser<CellTag>::Type).

Alternate Alternate approach

Maybe we should place in dax/exec/Cell.h the following:

typedef dax::exec::Cell<dax::CellTagTriangle> CellTriangle;
typedef dax::exec::Cell<dax::CellTagHexahedron> CellHexahedron;
...

This gives user the ability to refer to cell types with a non templated name, while at the same time allowing the tag dispatching to work properly Robert Maynard 13:21, 19 November 2012 (EST)

Acknowledgements

Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin Corporation, for the U.S. Department of Energy's National Nuclear Security Administration under contract DE-AC04-94AL85000.

SandiaLogo.png DOELogo.png

SAND 2012-9842P