How To Write Worklets

From Daxtoolkit
Jump to: navigation, search

What is a Worklet

The computational unit of the Dax Toolkit is the Worklet. Worklets are stateless functor that act on an extremely small area of interest ( like every point of a mesh ). The worklets are designed to be small independent units so that Dax is able to manage execution of the worklets in parallel easily. Worklets must explicitly state what information they need as input and what information they are going to write out, so that managing the execution is possible. Also since the worklets are running in parallel no communication between worklets are possible.

Lets look at the CellGradient worklet:

struct CellGradient : dax::exec::WorkletMapCell
{
#typedef void ControlSignature(Topology, Field(Point), Field(Point), Field(Out));
#typedef _4 ExecutionSignature(_1,_2,_3);
 
template<class CellTag>
  DAX_EXEC_EXPORT
  dax::Vector3 operator()(
      CellTag cellTag,
      const dax::exec::CellField<dax::Vector3,CellTag> &coords,
      const dax::exec::CellField<dax::Scalar,CellTag> &pointField) const
  {
    dax::Vector3 parametricCellCenter =
        dax::exec::ParametricCoordinates<CellTag>::Center();
    return dax::exec::CellDerivative(parametricCellCenter,
                                     coords,
                                     pointField,
                                     cellTag);
  }

Now to execute the CellGradient worklet for all cells in a uniform grid we would write the following code.

{
 
using namespace dax::cont;
 
UniformGrid<> grid();
//make a 10 by 10 by 10 grid of spacing size 1
grid.SetExtent(dax::make_Id3(0, 0, 0), dax::make_Id3(10, 10, 10));
 
//make a dummy field for our example full of one's
std::vector<dax::Scalar> f(grid.GetNumberOfPoints(), 1.0);
 
ArrayHandle<dax::Scalar> field = make_ArrayHandle(f);
ArrayHandle<dax::Vector3> gradient;
 
Schedule<> scheduler;
scheduler(grid,grid.GetPointCoordinates(),field,gradient);
 
//we now can copy the results back to the control environment into any container using
//the benifit of this syntax is that the memory is copied directly from execution to your container.
std::vector<dax::Vector3> results;
gradient.CopyInto(std::back_inserter(results));
 
//we can also use the array handles portal, which copies the memory from execution
//to internal storage of the array handle. 
gradient.GetPortalConstControl().Get(0); //will return the first value in the gradient;
 
 
}


Types of Worklets

All worklets must inherit from one of the current worklet types provided in dax. The current worklet types are WorkletMapField, WorkletMapCell, WorkletGenerateTopology, and WorkletInterpolatedCell. In the future we are looking to add worklet types for Edges and Faces.


WorkletType Description
WorkletMapField Execute a worklet on an arbitrary field length with no explicit access to any geometry or topological information.

You can still access the points of the mesh by explicitly passing them as a parameter.

WorkletMapCell Execute the worklet for all cells in the input topology. Allows you access to both the cell information, and point fields

defined for that cell. For point field access see the Point ControlTag.

WorkletGenerateTopology Execute a worklet that creates new topology based on previously generated point coordinates. Algorithms

that generate a subset of an original data sets cells would use this worklet type. The first parameter of the worklet must be the input topology, and the second parameter must be the output topology.

WorkletInterpolatedCell Execute the worklet that generates new point and topology. Example algorithms that use this worklet are

Slicing and MarchingCubes. The first control parameter of the worklet must be the input topology, the second parameter is the Geometry that we are creating.

Components of a Worklet

Control Signature

The ControlSignature typedef parameters define how we interpret the parameters that the users passes to the scheduler. Each argument in the signature is composed of two parts the Type and Context. The Type describe the domain of the argument, be it a Field or Topology. The Context describe how we will use the argument. The Context keywords that are currently available are In, Out, Point, Cell.

Now not all Context types make sense for all worklet types. The worklet type WorkletMapField has no domain, so the concept of Point or Cell is unsupported. Currently In and Out are supported on all Worklet types, while WorkletMapCell also understands Point and Cell.

The only complexity to the system is that due to the fact that data sets in Dax don't store properties you can't use the Point context keyword without also have a Topology argument in the signature. This is used to determine the points in the cell and the fields values at those points.

The best way to learn is to see some examples so lets dive right into understanding what some example ControlSignatures mean.

struct In : dax::exec::WorkletMapField
{
  typedef void ControlSignature(Field(In));
};

A pointless worklet! The first argument is a ready only Field. Lets move onto something a bit more complex.

struct InAndOut: dax::exec::WorkletMapField
{
#typedef void ControlSignature(Field(In),Field(Out));
};

The control signature here defines two arguments where the first is read only and the second is can be written two.

struct InAndOutCell: dax::exec::WorkletMapCell
{
  typedef void ControlSignature(Field(In),Field(Out));
//this signature is identical to the more verbose
//typedef void ControlSignature(Field(Cell,In),Field(Cell,Out));
};

Look carefully at this worklet compared to the previous one. The subtle difference is that we know inherit from WorkletMapCell. The Field keyword here means a cell centered field. Now since we don't pass in Topology or a Point field argument the end effect means that this worklet control signature is identical to the previous.

struct ComplexWorklet: dax::exec::WorkletMapCell
{
  typedef void ControlSignature(Topology, Field, Field(Point,Out));
//this signature is identical to the more verbose
//typedef void ControlSignature(Topology, Field(Cell,In), Field(Point,Out));
};

The inheritance from WorkletMapCell means we will execute over cells. The control signature tells us that the first parameter is geometric, second an ready only CellField and the last parameter is a Point Field that we can write too.

struct ComplexWorklet: dax::exec::WorkletMapCell
{
  typedef void ControlSignature(Field, Field(Point,Out));
};

This is an invalid worklet signature! As we referenced above the Point context keyword can't be used without also having a Topology argument. So lets fix this signature by adding a third argument.

struct ComplexWorklet: dax::exec::WorkletMapCell
{
  typedef void ControlSignature(Field, Field(Point,Out), Topology);
};

Execution Signature

The execution signature shows how we are going to transform the control signature to match the worklets '()' operator. The execution signature has to match worklets '()' operator and can use a control signature argument multiple times, or not use one at all.

Again lets walk through some execution signatures to learn how to use them.

struct In : dax::exec::WorkletMapField
{
  typedef void ControlSignature(Field(In), Field(Out) );
  typedef void ExecutionSignature(_1,_2);
};

This is a pretty simple execution signature. We are stating that the operators first parameter is the first control signature argument, and the second parameter is the second control argument.

struct In : dax::exec::WorkletMapField
{
  typedef void ControlSignature(Field(In), Field(Out) );
  typedef _2 ExecutionSignature(_1);
};

Now we are starting to see some interesting execution signatures. Instead of stating the second control argument will the second worklet parameter we will instead return that type.


We can also transform control signature parameters. Currently the only transformation is the Vertices, So lets see what that does:

struct In : dax::exec::WorkletMapCell
{
  typedef void ControlSignature(Topology(In), Topology(Out) );
  typedef void ExecutionSignature( _1, Vertices(_2) );
};


So the default behavior of the Topology control signature is that it provides you with a tag that describes the type of cell. The issue with this is that if you want to modify the topology of the cell it is impossible! To solve the problem you mark up the execution parameter with Vertices. This allows you to write out the new cells topology. This is a complex operation so lets show the entire functor that does this:

class ThresholdTopology : public dax::exec::WorkletGenerateTopology
{
public:
  typedef void ControlSignature(Topology, Topology(Out));
  typedef void ExecutionSignature( _1, Vertices(_2) );
 
  template<class InputCellTag, class OutputCellTag>
  DAX_EXEC_EXPORT
const void operator()(const dax::exec::CellVertices<InputCellTag> &inVertices,
                  dax::exec::CellVertices<OutputCellTag> &outVertices) const
  {
  outVertices.SetFromTuple(inVertices.GetAsTuple());
  }
};


Execution Signature also has a secondary role, it is the place where you can state you want access to other information that doesn't come from the control signature. The primary example is you want to know the current WorkletIndex. The worklet index is a value beween 0 and N where N is the size of the field you are executing on.

struct In : dax::exec::WorkletMapField
{
#typedef void ControlSignature(Field(Out));
#typedef void ExecutionSignature(WorkId,_1);
 
template<typename T>
void operator()(dax::Id index, T & t) const
{
   t = static_cast<T>(index);
}
};


Operator

Control Signature Type and Context Options

Type Context Example Support Worklet(s) Description
Field In Field(In) All Worklet types Read Only field, In is the default Context if none is listed for a type.
Field Out Field(Out) All Worklet types Field to save values to. If used as a parameter to the worklet you can read the current values

in the field.

Field Cell Field(Cell) or Field(Cell,Out) WorkletMapCell, WorkletGenerateTopology, and WorkletInterpolatedCell Describes a field as being a cell centered property. Can be combined with the In and Out context to create input and output cell fields.
Field Point Field(Point) or Field(Point,Out) WorkletMapCell, WorkletGenerateTopology, and WorkletInterpolatedCell Gives all the point field values for the given cell. Any worklet that uses this Context must also provide a Topology argument type.
Topology In Topology(In) WorkletMapCell, WorkletGenerateTopology, and WorkletInterpolatedCell Gives the cell as the functor parameter.
Topology Out Topology(Out) WorkletMapCell, WorkletGenerateTopology, and WorkletInterpolatedCell Currently only usable with the

Execution Modifier Vertices. The reasoning is that currently cells in Dax are read only. So the only thing you can modify are the point ids, which you must explicitly ask for in the execution signature.

Geometry Out Geometry(Out) WorkletInterpolatedCell Allows you to create both new topology and point coordinates for a cell.

Execution Signature Tags

Execution Signature Tags Description
_1, _2, _3 ... _10 References the argument position in the control structure that should be placed at this location in the '()' operator call.
WorkId gives you the current iteration index value.
VisitIndex Used with WorkletGenerateTopology and WorkletInterpolatedCell to describe how many times the algorithm has already visited the input cell you have been passed - Vertices(_N) Used with a Topology Control Type to allow you access to read and write to a cells point ids.

PermutationContainer

Sometimes you need the ability to schedule a worklet that doesn't operate on all the items in a field. Maybe you want to access a field that is sparse populated. In both cases the PermutationContainer is the class you want.

Examples