Comparing Isosurface With and Without Scatter Classes

From VTKM
Revision as of 19:57, 8 November 2015 by Kmorel (talk | contribs)
Jump to navigation Jump to search

We have recently added scatter classes to VTK-m, which allows building worklets that have a variable amount of output rather than a 1:1 relationship. This is particularly important for algorithms like isosurface that require specifying some amount of output depending on values of the input. Before these scatter classes were introduced, algorithms like isosurface had to build their own indices and then perform their own cross lookup. In addition to being inconvenient and difficult to read, it also meant that the algorithm could not take advantage of other VTK-m features available in the dispatcher/transport/fetch location.

This document compares the implementation of isosurface just before moving to scatter and just after.

The Code

The classify cell part of the isosurface algorithm has remained essentially the same, so we'll ignore that part. The implementation of the generate part of the algorithm has changed significantly in this transformation. We will look at the code in parts and compare the implementations directly.

Worklet State

Because the original implementation had to build its own indices and perform its own data lookups, it had to store array portals in the state of the worklet as well as auxiliary metadata so that the data could be reconstructed in the body of the worklet. In contrast, the new implementation can leverage VTK-m's built in ability to perform these data lookups. All that needs to be specified in the state is the Scatter class being used.

    const FieldType Isovalue;
    vtkm::Id xdim, ydim, zdim;
    const float xmin, ymin, zmin, xmax, ymax, zmax;

    typedef typename vtkm::cont::ArrayHandle<FieldType>::
        template ExecutionTypes<DeviceAdapter>::PortalConst FieldPortalType;
    FieldPortalType Field, Source;

    typedef typename vtkm::cont::ArrayHandle<vtkm::Vec<FieldType, 3> >::
        template ExecutionTypes<DeviceAdapter>::Portal VectorPortalType;
    VectorPortalType Vertices;
    VectorPortalType Normals;

    typedef typename vtkm::cont::ArrayHandle<FieldType>::
        template ExecutionTypes<DeviceAdapter>::Portal OutputPortalType;
    OutputPortalType Scalars;

    typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
    typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst
        IdPortalType;
    IdPortalType TriTable;

    const vtkm::Id cellsPerLayer, pointsPerLayer;
    const FieldType Isovalue;
    ScatterType Scatter;
Original Implementation New implementation

As the amount of state has dramatically reduced, so has the the complexity of the constructor.

    template<typename U, typename W, typename X>
    VTKM_CONT_EXPORT
    IsoSurfaceGenerate(FieldType ivalue, const vtkm::Id3 cdims,
                       IdPortalType triTablePortal,
                       const U & field, const U & source,
                       const W & vertices, const W & normals,
                       const X & scalars) :
      Isovalue(ivalue),
      xdim(cdims[0]), ydim(cdims[1]), zdim(cdims[2]),
      xmin(-1), ymin(-1), zmin(-1), xmax(1), ymax(1), zmax(1),
      Field( field.PrepareForInput( DeviceAdapter() ) ),
      Source( source.PrepareForInput( DeviceAdapter() ) ),
      Vertices(vertices),
      Normals(normals),
      Scalars(scalars),
      TriTable(triTablePortal),
      cellsPerLayer(xdim * ydim),
      pointsPerLayer ((xdim+1)*(ydim+1))
    {
    }
    template<typename CountArrayType, typename Device>
    VTKM_CONT_EXPORT
    IsoSurfaceGenerate(FieldType isovalue,
                       const CountArrayType &countArray,
                       Device)
      : Isovalue(isovalue), Scatter(countArray, Device()) {  }
Original Implementation New implementation

Signatures

Because the new implementation passes data through the dispatcher's invoke interface rather than as array state. Consequently, the interface of the ControlSignature and ExecutionSignature are much longer in the new interface, but they also specify more features of the transport/fetch.

    typedef void ControlSignature(FieldIn<IdType> inputCellId,
                                  FieldIn<IdType> inputIteration);
    typedef void ExecutionSignature(WorkIndex, _1, _2);
    typedef void ControlSignature(
        TopologyIn topology, // Cell set
        FieldInPoint<> fieldIn, // Input point field defining the contour
        FieldInPoint<Vec3> pcoordIn, // Input point coordinates
        FieldOutCell<> vertexOut, // Vertices for output triangles
        // TODO: Have a better way to iterate over and interpolate fields
        FieldInPoint<Scalar> scalarsIn, // Scalars to interpolate
        FieldOutCell<> scalarsOut, // Interpolated scalars (one per tri vertex)
        FieldOutCell<> normalsOut, // Estimated normals (one per tri vertex)
        ExecObject TriTable // An array portal with the triangle table
        );
    typedef void ExecutionSignature(
        CellShape, _2, _3, _4, _5, _6, _7, _8, VisitIndex);
Original Implementation New implementation

Likewise, the interface to the parentheses operator has grown commensurately.

    VTKM_EXEC_EXPORT
    void operator()(vtkm::Id outputCellId,
                    vtkm::Id inputCellId,
                    vtkm::Id inputLowerBounds) const
    template<typename CellShapeTag,
             typename FieldInType, // Vec-like, one per input point
             typename CoordType, // Vec-like (one per input point) of Vec-3
             typename VertexOutType, // Vec-3 of Vec-3 coordinates (for triangle)
             typename ScalarInType, // Vec-like, one per input point
             typename ScalarOutType, // Vec-3 (one value per tri vertex)
             typename NormalOutType, // Vec-3 of Vec-3
             typename TriTablePortalType> // Array portal
    VTKM_EXEC_EXPORT
    void operator()(
        CellShapeTag shape,
        const FieldInType &fieldIn, // Input point field defining the contour
        const CoordType &coords, // Input point coordinates
        VertexOutType &vertexOut, // Vertices for output triangles
        // TODO: Have a better way to iterate over and interpolate fields
        const ScalarInType &scalarsIn, // Scalars to interpolate
        ScalarOutType &scalarsOut, // Interpolated scalars (one per tri vertex)
        NormalOutType &normalsOut, // Estimated normals (one per tri vertex)
        const TriTablePortalType &triTable, // An array portal with the triangle table
        vtkm::IdComponent visitIndex
        ) const
Original Implementation New implementation
Original Implementation New implementation